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

时间:2018-07-01 21:41:50

标签: javascript

使用对象文字表示法创建Javascript对象时,如下所示:

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

然后,我可以像这样更改name的{​​{1}}属性的属性:

objectLiteralCat

太好了,现在没有人可以删除Object.defineProperty(objectLiteralCat,'name', {configurable: false}); 属性或更改其可枚举的属性。

我正在尝试创建原型模式对象的“味道”,我想使用Object.defineProperty像上面一样设置名称Property Attribute objectLiteralCat.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

然后按预期输出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}); 不会调用objectLiteralCat

Object.defineProperty

Object.defineProperty(objectLiteralCat,'name', {configurable: false}); 设置为objectLiteralCat.name,例如:

undefined

我的Object.defineProperty(self,'name', {configurable: false}); 函数可以使用吗?

即使我注释掉Cat.create中的Object.define代码,并在创建Cat.create对象后将其移到外部,如下所示:

cat

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

我的undefined对象:

objectLiteralCat

与我的“原型模式对象创建风格”基本相同。

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创建的对象的所有属性都嵌套在Cat.create

enter image description here

我确信这是我的问题的答案的线索,但是我对Javascript的了解还不够高,无法在没有帮助的情况下找出答案。

2 个答案:

答案 0 :(得分:3)

区别在于,在对象文字中,objectLiteralCat.name指的是name上的objectLiteralCat对象。另一方面,调用Cat.create时,您做了两个 name:一个在原型对象(位于Cat.name的对象上),另一个在原型对象上。在self对象上。 Object.defineProperty不会查找原型链来确定在任何原型对象上传递的传递的属性名称在何处/是否传递,而是Object.defineProperty在传递给它的对象上立即定义属性 ,在这种情况下为self

但是,之前

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

被称为对self.name的引用-即在行中

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

将使用name属性引用原型链中最接近的对象-这是Cat.name对象。为了说明,请查看实例化猫如何使Cat.name原型对象发生突变:

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});

这直接在{em> name而不是原型上设置self属性。但是您尚未传递任何value,因此它默认为undefinedname属性现在在原型对象(Cat.name.firstCat.name.last)上都存在,在实例化的{{1}上,都存在 }(=== cat)。

也许您想在开始时直接在undefined上显式创建一个新的name属性,之前分配给self

self.name.first

答案 1 :(得分:2)

尽管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};