繁体   English   中英

将新属性分配给具有冻结原型的空对象

[英]Assign new property to empty object which has frozen prototype

为什么我不能为具有冻结原型的非冻结对象分配新属性:

在没有 Object.freeze 的情况下工作:

'use strict'
//This object will be prototype of next objects
var defaults = {
  name: 'def name', 
  sections: {
    1: {
      secName: 'def sec name'
    }
  }
};

//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);


specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true

specificObject.sections['1'] = Object.create(defaults.sections['1']);

上面的代码按预期工作,但我想确保不会意外更改默认值。 所以我想冻结我的默认对象:

'use strict'
//This object will be prototype of next objects
var defaults = {
  name: 'def name', 
  sections: {
    1: {
      secName: 'def sec name'
    }
  }
};

//!!!!!!!!!!!!
Object.freeze(defaults);

//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);

//TypeError: Cannot assign to read only property 'sections' of #<Object>
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true

specificObject.sections['1'] = Object.create(defaults.sections['1']);

我不明白的是,如果其原型被冻结,为什么我不能分配给 specificObject?

//编辑:注意特定对象没有被冻结:

'use strict'
//This object will be prototype of next objects
var protoObj = {a: 1, o: {}};
Object.freeze(protoObj);

console.log(Object.isFrozen(protoObj)); //true

var n = Object.create(protoObj);
console.log(Object.isFrozen(n)); //false

我的理解是specificObject.sections指向它的原型,这是defaults ,它是冻结对象。 您定义了一个新对象{}但您尝试将其分配给defaults.sections SpecificObject.sections正好指向那里。

如果您在 specificObject 上创建新的ownProperty它将起作用:

'use strict'
//This object will be prototype of next objects
var defaults = {
  name: 'def name',
  sections: {
    1: {
      secName: 'def sec name'
    }
  }
};

//!!!!!!!!!!!!
Object.freeze(defaults);

//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);

// this will create new property
Object.defineProperty(specificObject, 'sections',{
    enumerable: true,
    writable: true,
    configurable: true,
    value: {}
});
console.log(specificObject.hasOwnProperty('sections')); //true

specificObject.sections['1'] = Object.create(defaults.sections['1']);

解释:

如果您尝试访问obj.prop = val则 javascript 会查看obj自己的属性,如果未找到,则它会查看obj的原型自己的属性。 如果在那里找到,那么它/尝试将val分配给/查找该属性。 如果在那里找不到,那么它会尝试查看obj的原型的原型等等。 如果在prototype树中找不到prop ,那么它会在obj上创建新的自己的属性并分配val

因此,如果在原型上找到prop并且它被冻结,你会得到类型错误。 希望它带来一些启发。:)

编辑:

正如@KubaWyrostek specificObj.sections = {}正确指出的那样,将创建特定对象的新属性,不会为原型的属性分配新值,但它可能会查找属性以检查可写性,在这种情况下它会碰到冻结的物体。 我之前不知道这件事。

我不明白的是,如果其原型被冻结,为什么我不能分配给specificObject

因为属性属性是继承的。 是的,这很奇怪。

如果您冻结一个对象,它会将所有数据属性的[[writable]]属性设置为false

如果您分配给一个对象属性,但该属性在该对象上不存在,它将在原型上查找它 - 它可能在那里被定义为 setter。 当此查找返回并说有该名称的属性但不可写时,您的赋值将失败(并在严格模式下抛出)。

对此你能做些什么?

  • 使用Object.defineProperty而不是赋值,它不检查原型
  • 或者类似的,使用Object.create的第二个参数来创建自己的属性
  • 仅在您分配给specificObject后冻结defaults

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM