【问题标题】:Setting enumerable property on object prototype在对象原型上设置可枚举属性
【发布时间】:2014-02-28 01:24:51
【问题描述】:

我正在尝试使用 setter 在对象原型上设置可枚举属性。

function Foo(){}
Object.defineProperty(Foo.prototype, 'tag', {
    enumerable: true, configurable: true,
    set: function(x){ 
        if(typeof(x) == "string") {
            Object.defineProperty(this, 'tag', {value: x});
        }
    }
});
var bar = new Foo();

bar.tag = 7;     console.log(bar.tag); // undefined
bar.tag = "baz"; console.log(bar.tag); // "baz"

console.log(bar); // {}
console.log(bar.propertyIsEnumerable('tag')); // false

一切都按预期工作,除了最后两行。
我刚刚测试了节点 v0.10.25 中的代码。我不明白为什么属性标签不可枚举。
作为一种解决方法,我在构造函数中针对this 使用Object.defineProperty 而不是Foo.prototype,但我想了解为什么javascript 中的对象不能从可枚举的属性继承。

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    问题是您的两个Object.defineProperty 调用定义了不同的属性:

    • 原型上的一个 setter 属性
    • 每个this 上都有一个值属性,即实例

    虽然原型上的那个是可枚举和可配置的,但实例属性不会“继承”这些描述符;他们将在新描述符上default to false。您需要明确设置它们:

    Object.defineProperty(Foo.prototype, 'tag', {
         enumerable: true, configurable: true,
         set: function(x){ 
             if (typeof(x) == "string")
                 Object.defineProperty(this, 'tag', {
                     enumerable:true, configurable:true, // still non-writable
                     value: x
                 });
         }
    });
    

    【讨论】:

    • 嗨,Bergi,当我将调用对象设置为 Foo.prototype 时发生了一些奇怪的事情,而 setter 中的 this 将引用相同的 tag member:Foo.prototype.tag = "hello"; console.log(bar); // { tag="hello" } console.log(bar.propertyIsEnumerable('tag')); // false,即使 enumerable 为 false记录的“栏”显示“标签”成员(在带有 FireBug 的 Firefox 中)。我想这是因为 bar 没有自己的名为 tag 的属性:console.log(Foo.prototype.propertyIsEnumerable('tag')); //=true
    • 我想说你需要Object.getPrototypeOf(bar).propertyIsEnumerable('tag') // true,因为这仅适用于自己的属性,而bar还没有:-)
    • 是的,正确的:console.log(bar.propertyIsEnumerable('nonexisting')); // false 我猜propertyIsEnumerable 将在对象hasOwnProperty 为假时返回假。找不到参考,但似乎是这样。
    【解决方案2】:

    您在 set 函数中重新分配标签(通过在名为 bar 的 Foo 实例上创建成员来隐藏标签)但不要将其设置为可枚举或可配置尝试以下操作:

    function Foo(){}
    Object.defineProperty(Foo.prototype, 'tag', {
        enumerable: true, configurable: true,
        set: function(x){ 
            if(typeof(x) == "string") {
                Object.defineProperty(this, 'tag', {
                  value: x,
                  enumerable: true
                });
            }
        }
    });
    var bar = new Foo();
    
    bar.tag = 7;     console.log(bar.tag); // undefined
    bar.tag = "baz"; console.log(bar.tag); // "baz"
    
    console.log(bar); // { tag="baz" }
    console.log(bar.propertyIsEnumerable('tag')); // true
    

    更多关于影子成员、构造函数和原型的信息:https://stackoverflow.com/a/16063711/1641941

    【讨论】:

      【解决方案3】:

      我认为你只能为对象定义属性,不能在原型或构造函数上定义,另见this post

      这就是为什么将object.defineProperty 放在构造函数中起作用的原因:this 在构造函数中是一个对象。

      【讨论】:

      • 不,原型可以设置成任何你喜欢的东西。您可以使用defineProperty、defineProperties 或Object.create 来设置原型的值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-23
      • 2017-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多