为何手动创建对象中的Getter函数与fur_get函数返回结果不同?
先来看你的代码:
animal = Object.create({}) Object.assign(animal, { _fur: 'This might not be furry', get fur() { return this._fur }, fur_get: function () { return this._fur } }) cat = Object.create(animal) Object.assign(cat, { _fur: 'This is very furry' }) console.log(cat.fur) // 输出:This might not be furry console.log(cat.fur_get()) // 输出:This is very furry
这里的核心问题藏在Object.assign对访问器属性的特殊处理和函数调用的this绑定规则里,我给你拆解明白:
1. Object.assign没把getter复制给animal,只复制了它的返回值
当你用Object.assign把带有get fur()的对象合并到animal时,它不会直接把这个getter访问器加到animal上。它会先调用源对象的fur getter(此时getter里的this指向那个临时的源对象,拿到源对象的_fur值:'This might not be furry'),然后把这个字符串作为普通数据属性赋值给animal。也就是说,animal.fur现在就是个固定的字符串,根本不是动态的getter了!
你可以用Object.getOwnPropertyDescriptor(animal, 'fur')验证,会发现它只有value字段,完全没有get相关的配置。
2. 普通函数fur_get的this会绑定到调用它的对象
而fur_get是个普通函数,Object.assign会直接把函数引用复制到animal上。当你通过cat.fur_get()调用时,属于方法调用模式,函数里的this会自动绑定到调用它的对象cat。所以this._fur会找到cat自己身上的_fur属性,返回'This is very furry'。
3. 访问cat.fur时拿到的是原型上的固定值
因为cat自己没有fur属性,JavaScript会顺着原型链找到animal上的fur——但这个fur是个静态的字符串,不会动态去读取this._fur,自然就返回当初的固定值了。
怎么改才能让getter正常工作?
如果想让animal拥有真正的动态getter,别用Object.assign,直接用Object.defineProperty定义:
animal = Object.create({}) animal._fur = 'This might not be furry' Object.defineProperty(animal, 'fur', { get: function() { return this._fur } }) animal.fur_get = function() { return this._fur } // 后续代码不变 cat = Object.create(animal) Object.assign(cat, { _fur: 'This is very furry' }) console.log(cat.fur) // 此时会输出:This is very furry console.log(cat.fur_get()) // 同样输出:This is very furry
这样animal的fur才是真正的访问器属性,访问cat.fur时,getter里的this会指向cat,从而读取它自己的_fur。
内容的提问来源于stack exchange,提问作者Jeremy Murray-Wakefield

