javascript引擎如何在具有该属性的setter的原型的对象上设置属性?

时间:2014-12-03 05:46:50

标签: javascript

我一直认为,当一个对象调用[[set]](或者它是[[put]]?时,引擎总是将属性分配(或尝试)到该对象,而不管它是什么原型。

但今天我试过这个

parent={
    set num(v){
        alert();
    }
}

obj=Object.create(parent);

obj.num=123;

它调用了setter,那么当引擎设置属性时会发生什么?它是否遍历原型链以检查它是否首先有任何setter?

1 个答案:

答案 0 :(得分:3)

引擎执行它始终执行的操作,即首先在实例上查找属性,然后在实例中查找原型链中的属性。如果使用setter定义属性(无论在何处找到并定义),则执行setter。在您的情况下,它在原型父级中找到该属性,并执行setter,显示警报。实际上没有设置。 (当然,如果未使用setter定义属性,则在实例上设置该值。)

如果要在实例本身上使用相同的名称实际创建属性,可以使用defineProperty(或Object.create的第二个参数)来实现。此属性将在原型上以相同名称“隐藏”(隐藏)该属性。下次尝试设置属性时,引擎将在实例上找到该属性,并在那里设置它(除非您在实例上定义的属性也有一个setter,在这种情况下将调用setter)。 p>

请注意,setter本身不进行任何设置。无论你想做什么设置,你都必须自己做。例如,您可能希望通过_num来设置代理属性,例如this._num = v。显然,this这里是实例 - 即使在原型上定义了setter - 因此_num属性将在实例上。如果你试图在setter中做this.num = v,你将得到一个无限循环,因为那将再次调用相同的setter。 num不能同时是基于getter / setter和普通值属性的属性。

请考虑以下事项:

parent = { set num(v) { alert(v); } };
obj = Object.create(parent);
obj.num = 44;  // alert

obj2 = Object.create(parent, { num: { value: 55 } });
obj2.num = 99  // proto ignored, no alert, simple assignment