使用对象文字表示法创建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
我确信这是我的问题的答案的线索,但是我对Javascript的了解还不够高,无法在没有帮助的情况下找出答案。
答案 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
,因此它默认为undefined
。 name
属性现在在原型对象(Cat.name.first
和Cat.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};