其他内置对象(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. 能解决什么问题 + 为什么重要

解决的问题

  1. 对象操作:Object 提供对象操作的工具方法
  2. 函数操作:Function 提供函数相关的操作
  3. 错误处理:Error 及其子类用于错误处理和调试
  4. 异步处理:Promise 简化异步编程
  5. 唯一标识: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");  // true

Object 的实例方法

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);  // true

4.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);  // 9

Function.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:错误处理,ErrorTypeErrorReferenceError
  • Promise:异步处理,then()catch()all()race()
  • Symbol:唯一标识符,用作对象键避免冲突

记忆口诀

  • Object - 对象操作
  • Function - 函数操作
  • Error - 错误处理
  • Promise - 异步承诺
  • Symbol - 唯一标识

10. 知识体系延伸 & 继续学习方向

继续学习方向

  1. 相关内置对象

  2. 相关主题

  3. 进阶学习

遵守仓库规范


参考资源


javascript Object Function Error Promise Symbol 内置对象