讲解

对象的属性值是函数时,这个属性就叫「方法」。方法通过 对象.方法名() 调用,调用时方法内部的 this 指向调用它的对象,借此访问同对象的其他属性——比如一个 person 对象的 greet 方法里写 this.name 拿到自己的名字。this 的完整规则后面有专门章节,这里先记住一条:谁调用,this 就是谁。

对象的复制是个重要话题。直接赋值复制的只是引用;要复制内容得用展开语法 { ...obj } 或 Object.assign({}, obj)——但它们是「浅拷贝」:只复制第一层,嵌套对象仍然共享。深拷贝的现代方案是 structuredClone(obj)(浏览器和 Node 17+ 都有),老方案 JSON.parse(JSON.stringify(obj)) 会丢失 undefined、函数、日期等,只适用于纯数据。合并多个对象也用展开:{ ...defaults, ...options },后面的覆盖前面的。

Object 上还有一批实用静态方法:Object.assign 合并、Object.freeze 冻结(浅冻结,冻结后不能增删改属性)、Object.fromEntries 把键值对数组转回对象(与 Object.entries 互逆,配合 map/filter 可以对对象做「数组式」变换)、Object.getPrototypeOf 读原型。对象转数组、用数组方法处理、再转回对象,是处理对象的现代惯用套路。

示例

const counter = {
  value: 0,
  increment() {
    this.value++;
    return this.value;
  },
};
counter.increment();
counter.increment();
console.log('方法内 this 访问属性:', counter.value);

// 浅拷贝与嵌套共享
const original = { name: '小明', tags: ['a', 'b'] };
const shallow = { ...original };
shallow.tags.push('c');
console.log('原对象的 tags 也变了:', original.tags); // 嵌套数组被共享

// structuredClone 真深拷贝
const deep = structuredClone(original);
deep.tags.push('d');
console.log('深拷贝互不影响:', original.tags, deep.tags);

// 合并:后面的覆盖前面的
const defaults = { theme: 'light', fontSize: 14 };
const options = { fontSize: 18 };
console.log('合并配置:', { ...defaults, ...options });

// 对象做「数组式」变换:所有分数翻倍
const scoresMap = { 语文: 80, 数学: 90 };
const doubled = Object.fromEntries(Object.entries(scoresMap).map(([k, v]) => [k, v * 2]));
console.log('变换后:', doubled);

// 冻结
const config = Object.freeze({ env: 'prod' });
config.env = 'dev'; // 静默失败(严格模式下报错)
console.log('冻结后仍可读:', config.env);

常见坑

  • 以为展开是深拷贝:{ ...obj } 只拷第一层,嵌套对象/数组仍是共享引用,改了互相影响。深拷贝用 structuredClone。
  • 在回调中丢失 this:把 obj.method 单独取出来赋值给变量再调用,this 就丢了(变成 undefined 或全局对象)。这是 this 章节的核心坑。
  • JSON 深拷贝丢数据:JSON 方案会把 Date 变字符串、丢掉 undefined 和函数、遇到循环引用直接抛错。只用于确认是纯数据的场景。
  • 冻结只是浅冻结:Object.freeze 后嵌套对象仍可改。而且静默失败在非严格模式下不报错,排查困难。

小结

方法里的 this 指向调用者;浅拷贝用展开、深拷贝用 structuredClone;Object.entries + 数组方法 + fromEntries 是对象变换的惯用套路。下一节正式进入函数。