其他内置对象(Other Built-in Objects)
JavaScript 其他内置对象:Object、Function、Error 等,就像工具箱里的其他工具,各有各的用途。
1. 一句话概括主题
除了 Array、String、Date 等常用内置对象,JavaScript 还提供了 Object、Function、Error、Promise 等重要的内置对象,它们构成了 JavaScript 语言的核心基础。
2. 它是什么(像和朋友聊天一样解释)
想象一下,这些内置对象就像工具箱里的其他工具:
- Object → 就像”万能工具”,所有对象的”祖先”
- Function → 就像”函数工厂”,可以创建和操作函数
- Error → 就像”错误报告器”,告诉你哪里出错了
- Promise → 就像”承诺书”,处理异步操作的结果
- Symbol → 就像”唯一标识符”,创建独一无二的标识
举例:
// Object - 所有对象的基类
Object.keys({ a: 1, b: 2 }); // ["a", "b"]
// Function - 函数也是对象
function greet() {}
console.log(greet instanceof Function); // true
// Error - 错误处理
throw new Error("出错了!");
// Promise - 异步操作
Promise.resolve("成功").then(console.log);3. 能解决什么问题 + 为什么重要
解决的问题
- 对象操作:Object 提供对象操作的工具方法
- 函数操作:Function 提供函数相关的操作
- 错误处理:Error 及其子类用于错误处理和调试
- 异步处理:Promise 简化异步编程
- 唯一标识:Symbol 创建唯一的标识符
为什么重要
- 语言基础:这些对象是 JavaScript 语言的核心
- 日常开发:几乎每个程序都会用到这些对象
- 面试必考:这些对象是前端面试的高频考点
- 理解语言:理解这些对象有助于深入理解 JavaScript
4. 核心知识点拆解
4.1 Object 对象
Object 的静态方法
Object.keys() - 获取对象的所有键
const obj = { name: "张三", age: 25, city: "北京" };
Object.keys(obj); // ["name", "age", "city"]Object.values() - 获取对象的所有值(ES2017)
const obj = { name: "张三", age: 25, city: "北京" };
Object.values(obj); // ["张三", 25, "北京"]Object.entries() - 获取对象的键值对数组(ES2017)
const obj = { name: "张三", age: 25 };
Object.entries(obj); // [["name", "张三"], ["age", 25]]Object.assign() - 复制对象属性(ES6)
const target = { a: 1 };
const source = { b: 2, c: 3 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 2, c: 3 }
// 浅拷贝对象
const obj = { a: 1, b: 2 };
const copy = Object.assign({}, obj);Object.create() - 创建新对象(使用指定原型)
const proto = { greet() { return "Hello"; } };
const obj = Object.create(proto);
obj.name = "张三";
console.log(obj.greet()); // "Hello"Object.freeze() - 冻结对象(不可修改)
const obj = { name: "张三" };
Object.freeze(obj);
obj.name = "李四"; // 静默失败(严格模式下会报错)
console.log(obj.name); // "张三"(未改变)Object.seal() - 密封对象(不能添加/删除属性,但可以修改)
const obj = { name: "张三" };
Object.seal(obj);
obj.name = "李四"; // 可以修改
obj.age = 25; // 不能添加(静默失败)
delete obj.name; // 不能删除(静默失败)Object.defineProperty() - 定义对象属性
const obj = {};
Object.defineProperty(obj, "name", {
value: "张三",
writable: false, // 不可写
enumerable: true, // 可枚举
configurable: false // 不可配置
});
obj.name = "李四"; // 无效(writable: false)
console.log(obj.name); // "张三"Object.hasOwnProperty() - 检查属性是否为自有属性
const obj = { name: "张三" };
obj.hasOwnProperty("name"); // true
obj.hasOwnProperty("toString"); // false(继承自 Object.prototype)
// ES2022 新增:Object.hasOwn()(推荐使用)
Object.hasOwn(obj, "name"); // trueObject 的实例方法
const obj = { name: "张三", age: 25 };
// toString() - 转换为字符串
obj.toString(); // "[object Object]"
// valueOf() - 返回原始值
obj.valueOf(); // { name: "张三", age: 25 }
// hasOwnProperty() - 检查自有属性
obj.hasOwnProperty("name"); // true
// isPrototypeOf() - 检查是否为原型
Object.prototype.isPrototypeOf(obj); // true4.2 Function 对象
Function 的特点
// 函数是 Function 的实例
function greet() {}
console.log(greet instanceof Function); // true
// 函数也是对象
greet.name = "greet";
console.log(greet.name); // "greet"Function 的方法
Function.prototype.call() - 调用函数(指定 this)
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: "张三" };
greet.call(person, "Hello", "!"); // "Hello, 张三!"Function.prototype.apply() - 调用函数(参数为数组)
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: "张三" };
greet.apply(person, ["Hello", "!"]); // "Hello, 张三!"
// 实际应用:求数组最大值
const numbers = [1, 5, 3, 9, 2];
Math.max.apply(null, numbers); // 9Function.prototype.bind() - 绑定 this(返回新函数)
function greet() {
return `Hello, ${this.name}!`;
}
const person = { name: "张三" };
const boundGreet = greet.bind(person);
boundGreet(); // "Hello, 张三!"
// 实际应用:事件处理
class Button {
constructor() {
this.clickCount = 0;
// 绑定 this,确保事件处理函数中的 this 指向实例
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.clickCount++;
console.log(`点击了 ${this.clickCount} 次`);
}
}函数属性
function greet(name, age) {
return `Hello, ${name}!`;
}
// name - 函数名
console.log(greet.name); // "greet"
// length - 参数个数
console.log(greet.length); // 2
// arguments - 函数参数(类数组对象,已废弃)
function test() {
console.log(arguments); // 类数组对象
}4.3 Error 对象
Error 类型
// Error - 通用错误
throw new Error("发生错误");
// TypeError - 类型错误
throw new TypeError("类型错误");
// ReferenceError - 引用错误
throw new ReferenceError("引用错误");
// SyntaxError - 语法错误
throw new SyntaxError("语法错误");
// RangeError - 范围错误
throw new RangeError("范围错误");Error 的属性
try {
throw new Error("测试错误");
} catch (error) {
console.log(error.name); // "Error"
console.log(error.message); // "测试错误"
console.log(error.stack); // 堆栈跟踪信息
}自定义错误
class CustomError extends Error {
constructor(message, code) {
super(message);
this.name = "CustomError";
this.code = code;
}
}
try {
throw new CustomError("自定义错误", "ERR001");
} catch (error) {
if (error instanceof CustomError) {
console.log(error.code); // "ERR001"
}
}4.4 Promise 对象(ES6)
Promise 的基本用法
// 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve("成功");
} else {
reject("失败");
}
}, 1000);
});
// 处理结果
promise
.then(result => console.log(result)) // "成功"
.catch(error => console.error(error)); // 处理错误Promise 的静态方法
Promise.resolve() - 创建已解决的 Promise
Promise.resolve("成功").then(console.log); // "成功"Promise.reject() - 创建已拒绝的 Promise
Promise.reject("失败").catch(console.error); // "失败"Promise.all() - 等待所有 Promise 完成
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [1, 2, 3]
});Promise.race() - 返回第一个完成的 Promise
const p1 = new Promise(resolve => setTimeout(() => resolve(1), 100));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 50));
Promise.race([p1, p2]).then(value => {
console.log(value); // 2(先完成)
});4.5 Symbol 对象(ES6)
Symbol 的特点
// 创建 Symbol(每次都是唯一的)
const sym1 = Symbol("描述");
const sym2 = Symbol("描述");
console.log(sym1 === sym2); // false(即使描述相同也不同)
// 用作对象键
const obj = {};
obj[sym1] = "值1";
obj[sym2] = "值2";
console.log(obj[sym1]); // "值1"Symbol 的常用符号
// Symbol.iterator - 迭代器
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
// Symbol.toStringTag - 自定义 toString
class MyClass {
get [Symbol.toStringTag]() {
return "MyClass";
}
}
console.log(new MyClass().toString()); // "[object MyClass]"
// Symbol.toPrimitive - 自定义类型转换
const obj = {
[Symbol.toPrimitive](hint) {
if (hint === "number") return 42;
if (hint === "string") return "hello";
return "default";
}
};
console.log(+obj); // 42
console.log(String(obj)); // "hello"4.6 常见误解说明与纠正
误解 1:Object.assign() 是深拷贝
❌ 错误理解:
const obj = { a: { b: 1 } };
const copy = Object.assign({}, obj);
copy.a.b = 2;
console.log(obj.a.b); // 2(原对象也被修改了)✅ 正确理解:
Object.assign()是浅拷贝,只复制第一层属性- 嵌套对象是引用,修改会影响原对象
// 浅拷贝
const copy = Object.assign({}, obj);
// 深拷贝(需要其他方法)
const deepCopy = JSON.parse(JSON.stringify(obj)); // 有限制
// 或使用递归函数实现深拷贝误解 2:Function 和 function 关键字一样
❌ 错误理解:
- 认为
Function构造函数和function关键字完全一样
✅ 正确理解:
function关键字是声明函数的标准方式Function构造函数可以动态创建函数,但不推荐使用
// 推荐:使用 function 关键字
function greet(name) {
return `Hello, ${name}!`;
}
// 不推荐:使用 Function 构造函数
const greet2 = new Function("name", "return `Hello, ${name}!`");误解 3:Error 必须用 throw 抛出
❌ 错误理解:
- 认为 Error 对象必须用
throw抛出
✅ 正确理解:
- Error 对象可以创建但不抛出
- 可以用于记录错误信息
// 可以创建但不抛出
const error = new Error("错误信息");
console.log(error.message); // "错误信息"
// 也可以抛出
throw new Error("错误信息");5. 示例代码(可运行 + 逐行注释)
// ===== 示例 1:对象操作 =====
const user = { name: "张三", age: 25, city: "北京" };
// 1. 获取所有键
const keys = Object.keys(user);
console.log(keys); // ["name", "age", "city"]
// 2. 获取所有值
const values = Object.values(user);
console.log(values); // ["张三", 25, "北京"]
// 3. 获取键值对数组
const entries = Object.entries(user);
console.log(entries); // [["name", "张三"], ["age", 25], ["city", "北京"]]
// 4. 合并对象
const additional = { email: "zhangsan@example.com" };
const merged = Object.assign({}, user, additional);
console.log(merged); // { name: "张三", age: 25, city: "北京", email: "zhangsan@example.com" }
// ===== 示例 2:函数调用方法 =====
function introduce(greeting, punctuation) {
return `${greeting}, 我是${this.name},今年${this.age}岁${punctuation}`;
}
const person = { name: "张三", age: 25 };
// 1. 使用 call(参数逐个传递)
const result1 = introduce.call(person, "你好", "!");
console.log(result1); // "你好, 我是张三,今年25岁!"
// 2. 使用 apply(参数为数组)
const result2 = introduce.apply(person, ["你好", "!"]);
console.log(result2); // "你好, 我是张三,今年25岁!"
// 3. 使用 bind(绑定 this,返回新函数)
const boundIntroduce = introduce.bind(person);
const result3 = boundIntroduce("你好", "!");
console.log(result3); // "你好, 我是张三,今年25岁!"
// ===== 示例 3:错误处理 =====
function divide(a, b) {
// 1. 检查参数
if (typeof a !== "number" || typeof b !== "number") {
throw new TypeError("参数必须是数字");
}
// 2. 检查除数
if (b === 0) {
throw new RangeError("除数不能为 0");
}
return a / b;
}
// 3. 使用 try-catch 处理错误
try {
const result = divide(10, 2);
console.log(result); // 5
} catch (error) {
if (error instanceof TypeError) {
console.error("类型错误:", error.message);
} else if (error instanceof RangeError) {
console.error("范围错误:", error.message);
} else {
console.error("未知错误:", error.message);
}
}
// ===== 示例 4:Promise 使用 =====
// 1. 创建 Promise
function fetchData(url) {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
if (url) {
resolve({ data: "数据", url });
} else {
reject(new Error("URL 不能为空"));
}
}, 1000);
});
}
// 2. 使用 Promise
fetchData("https://example.com/api")
.then(result => {
console.log("成功:", result);
return result.data;
})
.then(data => {
console.log("数据:", data);
})
.catch(error => {
console.error("错误:", error.message);
});
// 3. 使用 async/await(ES2017)
async function getData() {
try {
const result = await fetchData("https://example.com/api");
console.log("成功:", result);
} catch (error) {
console.error("错误:", error.message);
}
}
// ===== 示例 5:Symbol 使用 =====
// 1. 创建 Symbol
const sym1 = Symbol("id");
const sym2 = Symbol("id");
// 2. 用作对象键(避免属性名冲突)
const user = {
name: "张三",
[sym1]: "用户ID1",
[sym2]: "用户ID2" // 即使描述相同,也是不同的键
};
console.log(user[sym1]); // "用户ID1"
console.log(user[sym2]); // "用户ID2"
// 3. 使用 Symbol 实现私有属性(约定)
const _private = Symbol("private");
class MyClass {
constructor() {
this[_private] = "私有数据";
this.public = "公开数据";
}
getPrivate() {
return this[_private];
}
}
const instance = new MyClass();
console.log(instance.public); // "公开数据"
console.log(instance.getPrivate()); // "私有数据"
// console.log(instance[_private]); // 可以访问,但不是真正的私有
// ===== 示例 6:对象冻结和密封 =====
// 1. Object.freeze() - 完全冻结
const frozen = { name: "张三" };
Object.freeze(frozen);
frozen.name = "李四"; // 无效
frozen.age = 25; // 无效
delete frozen.name; // 无效
console.log(frozen); // { name: "张三" }
// 2. Object.seal() - 密封(可以修改,不能添加/删除)
const sealed = { name: "张三" };
Object.seal(sealed);
sealed.name = "李四"; // 可以修改
sealed.age = 25; // 无效(不能添加)
delete sealed.name; // 无效(不能删除)
console.log(sealed); // { name: "李四" }6. 常见错误与踩坑
错误 1:Object.assign() 是深拷贝
错误代码:
const obj = { a: { b: 1 } };
const copy = Object.assign({}, obj);
copy.a.b = 2;
console.log(obj.a.b); // 2(原对象也被修改了)为什么错:
Object.assign()是浅拷贝,只复制第一层- 嵌套对象是引用,修改会影响原对象
正确方式:
// 方式 1:使用 JSON(有限制)
const deepCopy = JSON.parse(JSON.stringify(obj));
// 方式 2:递归深拷贝
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}错误 2:忘记绑定 this
错误代码:
class Button {
constructor() {
this.clickCount = 0;
}
handleClick() {
this.clickCount++;
console.log(`点击了 ${this.clickCount} 次`);
}
}
const button = new Button();
// 直接作为事件处理函数,this 会丢失
document.addEventListener("click", button.handleClick); // this 是 undefined为什么错:
- 函数作为回调时,
this会丢失 - 需要绑定
this或使用箭头函数
正确方式:
// 方式 1:使用 bind
class Button {
constructor() {
this.clickCount = 0;
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.clickCount++;
}
}
// 方式 2:使用箭头函数
class Button {
constructor() {
this.clickCount = 0;
}
handleClick = () => {
this.clickCount++;
}
}错误 3:Promise 错误处理不当
错误代码:
// 忘记处理 Promise 的错误
fetchData("url")
.then(result => console.log(result));
// 如果出错,错误会被静默忽略为什么错:
- Promise 的错误如果不处理,会被静默忽略
- 可能导致难以调试的问题
正确方式:
// 方式 1:使用 catch
fetchData("url")
.then(result => console.log(result))
.catch(error => console.error(error));
// 方式 2:使用 try-catch(async/await)
async function handleData() {
try {
const result = await fetchData("url");
console.log(result);
} catch (error) {
console.error(error);
}
}7. 实际应用场景
场景 1:对象合并和克隆
// 合并配置对象
const defaultConfig = { host: "localhost", port: 3000 };
const userConfig = { port: 8080, debug: true };
const config = Object.assign({}, defaultConfig, userConfig);
// { host: "localhost", port: 8080, debug: true }场景 2:错误处理
// API 请求错误处理
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("获取用户失败:", error.message);
throw error;
}
}场景 3:Promise 链式调用
// 处理多个异步操作
function processData() {
return fetchData("/api/data")
.then(data => transformData(data))
.then(transformed => saveData(transformed))
.then(() => console.log("处理完成"))
.catch(error => console.error("处理失败:", error));
}场景 4:Symbol 实现私有属性
// 使用 Symbol 实现"私有"属性(约定)
const _private = Symbol("private");
class Counter {
constructor() {
this[_private] = 0;
}
increment() {
this[_private]++;
}
getValue() {
return this[_private];
}
}8. 给新手的练习题
基础题
练习 1:对象操作
// 任务:获取对象的所有键和值
const obj = { name: "张三", age: 25 };
// 你的代码...
// 参考答案:
const keys = Object.keys(obj); // ["name", "age"]
const values = Object.values(obj); // ["张三", 25]练习 2:函数调用
// 任务:使用 call 调用函数,改变 this 指向
function greet() {
return `Hello, ${this.name}!`;
}
const person = { name: "张三" };
// 你的代码...
// 参考答案:
const result = greet.call(person); // "Hello, 张三!"练习 3:错误处理
// 任务:创建并抛出 TypeError
// 你的代码...
// 参考答案:
throw new TypeError("类型错误");进阶题
练习 4:实现深拷贝
// 任务:实现一个深拷贝函数
function deepClone(obj) {
// 你的代码...
}
// 测试
const obj = { a: 1, b: { c: 2 } };
const cloned = deepClone(obj);
cloned.b.c = 3;
console.log(obj.b.c); // 应该还是 2
// 参考答案:
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}练习 5:Promise 封装
// 任务:将 setTimeout 封装成 Promise
function delay(ms) {
// 你的代码...
}
// 测试
delay(1000).then(() => console.log("1秒后执行"));
// 参考答案:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}9. 用更简单的话再总结一遍(方便复习)
其他内置对象是 JavaScript 的核心工具:
- Object:对象操作工具,
keys()、values()、assign()等 - Function:函数操作,
call()、apply()、bind()改变 this - Error:错误处理,
Error、TypeError、ReferenceError等 - Promise:异步处理,
then()、catch()、all()、race()等 - Symbol:唯一标识符,用作对象键避免冲突
记忆口诀:
- Object - 对象操作
- Function - 函数操作
- Error - 错误处理
- Promise - 异步承诺
- Symbol - 唯一标识
10. 知识体系延伸 & 继续学习方向
继续学习方向
-
相关内置对象:
-
相关主题:
-
进阶学习:
遵守仓库规范
- 使用双链格式
[[xxx]]链接相关知识点 - 参考 内置对象概述 了解内置对象分类
- 参考 JavaScript MOC 了解完整知识体系
参考资源: