代码之家  ›  专栏  ›  技术社区  ›  Brian Ogden

原型对象创建模式中的object.defineProperty“未定义”值属性

  •  3
  • Brian Ogden  · 技术社区  · 7 年前

    使用object literal表示法创建javascript对象时,如下所示:

    var objectLiteralCat = {
      name: {first: 'frisky', last: 'LaBeouf'},
      color: 'Red'
    }
    

    然后我可以改变 name 财产 objectLiteralCat 就像这样:

    Object.defineProperty(objectLiteralCat,'name', {configurable: false});
    

    太好了,现在没人能删除 objectLiteralCat.name 属性或更改其可枚举属性。

    我正在尝试创建原型模式对象的“风格”,我想使用object.defineProperty设置name属性 configurable = false 如上所述,代码如下:

    var Cat = {
      create: function(firstName, lastName, color){
        var self = Object.create(this);
        self.name.first = firstName;
        self.name.last = lastName;
        Object.defineProperty(self,'name', {configurable: false});
        Object.freeze(self.name);
        Object.freeze(self.color);
        return self;
      },
      name: {first: '', last: ''},
      color: ''
    }
    
    var cat = Cat.create('frisky','smith','white');
    console.log(cat.name); //undefined

    如果,在 Cat.create 函数i注释行:

    Object.defineProperty(self,'name', {configurable: false});
    

    那么 console.log(cat.name) 预期的产出:

    Object {first: "frisky", last: "smith"}
    

    我可以显式地设置 value 的属性 Cat.name 性质如下:

    Object.defineProperty(self,'name', {value: self.name, configurable: false});
    

    我不明白的是为什么 目标语言 呼叫 Object.defineProperty 以下内容:

    object.defineProperty(objectLiteralcat,'name',{configurable:false});
    

    设置 objectliteralcat.name undefined 比如:

    object.defineProperty(self,'name',{configurable:false});
    

    在我的 创建类别 功能?

    即使我把 Object.define 代码输入 创建类别 然后把它移到外面 cat 对象的创建方式如下:

    var cat = Cat.create('fluffy', 'leboudf', 'white');
    Object.defineProperty(cat,'name', {configurable: false});
    console.log(cat.name);
    

    的输出 console.log(cat.name) 又来了 未定义 是的。

    我的 目标语言 对象:

    Object {
        name: [object Object]
        color: Red
    }
    

    从根本上看,我的“原型模式对象创建的味道”是一样的

    Object {
        create: function(firstName, lastName, color){
            var self = Object.create(this);
            self.name.first = firstName;
            self.name.last = lastName;
            //Object.defineProperty(self,'name', {value: self.name, configurable: false});
            Object.freeze(self.name);
            Object.freeze(self.color);
            return self;
        }
        name: [object Object]
        color:
    }
    

    看着 console.log 但是,这两个对象的所有属性看起来都是用 创建类别 嵌套在 __proto__

    enter image description here

    我确信这是我问题答案的一个线索,但是我还没有足够的javascript技术来在没有帮助的情况下找到答案。

    2 回复  |  直到 7 年前
        1
  •  3
  •   CertainPerformance    7 年前

    不同的是,在你的对象字面上, objectLiteralCat.name 指的是 name 对象立即打开 objectLiteralCat 是的。另一方面,打电话时 Cat.create ,你做的 名称 一个在原型物体上(物体在 Cat.name ,另一个在 self 反对。 Object.defineProperty 不查找原型链以标识传递的属性名在任何原型对象上的位置/是否在其中-而是, 对象定义属性 定义属性 就在传递给它的对象上 ,在本例中是 自己 是的。

    但是,以前

    Object.defineProperty(self,'name', {configurable: false});
    

    被调用,引用 self.name -也就是说,排队

    self.name.first = firstName;
    self.name.last = lastName;
    

    将使用 名称 属性-它是 类别名称 反对。为了演示,请参见实例化一个cat如何使 类别名称 原型对象:

    var Cat = {
      create: function(firstName, lastName, color){
        var self = Object.create(this);
        self.name.first = firstName;
        self.name.last = lastName;
        Object.defineProperty(self,'name', {configurable: false});
        Object.freeze(self.name);
        Object.freeze(self.color);
        return self;
      },
      name: {first: '', last: ''},
      color: ''
    }
    
    var cat = Cat.create('frisky','smith','white');
    
    // Log the prototype object: it's been mutated!
    console.log(Cat.name);

    之后,当你打电话

    object.defineProperty(self,'name',{configurable:false});
    

    这将设置 名称 财产 直接打开 自己 ,不在原型上。但你没有通过任何考试 value 所以它默认为 undefined 是的。这个 名称 属性现在存在 二者都 关于原型对象( Cat.name.first Cat.name.last )我是说, 在实例化的 cat (=== 未定义 )中。

    也许您想显式地创建一个新的 名称 直接打开属性 自己 一开始, 之前 分配给 self.name.first 以下内容:

    var Cat = {
      create: function(firstName, lastName, color){
        var self = Object.create(this);
        Object.defineProperty(self,'name', {configurable: false, value: {}});
        self.name.first = firstName;
        self.name.last = lastName;
        Object.freeze(self.name);
        Object.freeze(self.color);
        return self;
      },
      name: {first: '', last: ''},
      color: ''
    }
    
    var cat = Cat.create('frisky','smith','white');
    console.log(cat.name);
        2
  •  2
  •   Jonas Wilms    7 年前

    self 是继承 Cat 对象, self.name 仍然引用全局 Cat.name 是的。因此,如果您这样做:

    const obj = { prop: 1 }
    Object.defineProperty(obj, "prop", { /*...*/ })
    

    这是另一回事,作为财产 直接存在于对象本身 而且不是遗传的。如果它被继承,例如:

    const obj2 = Object.create(obj);
    Object.defineProperty(obj2, "prop", {/*...*/})
    

    然后 defineProperty 定义 对象本身的新属性 是的。它不认为它已经被设置在原型上了。所以你把它阴影化为未定义。要解决可能要为每个实例分配新对象的问题,例如:

    self.name = { first: firstName, last: lastName};