JavaScript引擎如何在具有原型的对象上设置属性,并为该属性设置一个setter

How do javascript engines set properties on objects that have prototypes with a setter for that property?

本文关键字:属性 设置 setter 一个 引擎 原型 JavaScript 对象      更新时间:2023-09-26

我总是觉得,当对对象调用[[set]](或者[[put]]?(时,引擎总是将属性分配给(或尝试(给该对象,而不管它的原型如何。

但是今天当我尝试这个

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

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

引擎执行它一贯执行的操作,即首先在实例上查找属性,如果不在实例上查找属性,则在原型链中查找属性。如果属性(无论在何处找到且以何种方式定义(都是使用资源库定义的,则执行资源库。在您的情况下,它会在原型父级中找到属性,并执行资源库,显示警报。实际上什么都没有设置。(当然,如果属性不是使用资源库定义的,则在实例上设置值。

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

请注意,二传手本身不进行设置。无论你想做什么设置,你都必须自己做。例如,您可能希望通过说 this._num = v 来设置代理属性,例如 _num 。显然,this这里是实例 - 即使 setter 是在原型上定义的 - 因此 _num 属性将位于实例上。如果你尝试在二传手内部执行this.num = v,你最终会得到一个无限循环,因为这会再次调用同一个二传手。 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