关于JavaScript对象属性设置和屏蔽技巧,我从下面的几个方面详细阐述:
我们可以使用 Object.preventExtensions()
方法来禁止对象增加属性。如果我们尝试给一个被禁止增加属性的对象增加属性,就会失败并抛出错误。
const obj = { a: 1, b: 2 };
Object.preventExtensions(obj);
obj.c = 3; // TypeError: Cannot add property c, object is not extensible
我们可以使用 Object.freeze()
方法来冻结对象,从而防止对象的属性被修改和删除。如果我们尝试修改和删除一个被冻结的对象,就会失败并抛出错误。
const obj = { a: 1, b: 2 };
Object.freeze(obj);
obj.a = 3; // TypeError: Cannot assign to read only property 'a' of object '#<Object>'
delete obj.b; // TypeError: Cannot delete property 'b' of #<Object> which is non-configurable and can't be deleted
// 可以通过 Object.isFrozen() 方法来检查一个对象是否被冻结
console.log(Object.isFrozen(obj)); // true
当我们给一个对象的属性设置了值后,我们可以通过屏蔽机制来控制访问该属性时返回的值。在访问属性时,JavaScript 引擎会检查该属性是否存在于对象本身上,如果不存在,它会沿着原型链一直查找到 Object.prototype 上。但是如果对象本身上存在该属性,无论该属性的值是什么,它都将遮盖原型链上该属性的值。
以下是一个示例:
const obj1 = { a: 1 };
const obj2 = {
b: 2,
get a() {
return 3;
}
};
console.log(obj1.a); // 1
console.log(obj2.a); // 3
Object.setPrototypeOf(obj1, obj2); // 将 obj1 的原型设置为 obj2
console.log(obj1.a); // 1,因为 obj1 本身有 a 属性,不需要沿着原型链查找
从上面的示例可以看出,当我们通过 Object.setPrototypeOf()
方法将 obj1 的原型设置为 obj2 时,尽管 obj2 上的 a 属性的值为 3,但是在访问 obj1.a 时返回的是 obj1 本身上的 a 属性的值 1。原因是对象本身上的属性值会覆盖原型链上的同名属性值。可以通过在子对象中重新定义该属性来解决这个问题。
以下是通过在子对象中重新定义该属性的示例:
const obj1 = { a: 1 };
const obj2 = {
b: 2,
get a() {
return 3;
}
};
console.log(obj1.a); // 1
console.log(obj2.a); // 3
Object.setPrototypeOf(obj1, obj2); // 将 obj1 的原型设置为 obj2
console.log(obj1.a); // 1,因为 obj1 本身有 a 属性,不需要沿着原型链查找
// 在 obj1 对象本身上重新定义 a 属性
Object.defineProperty(obj1, 'a', {
value: 4,
writable: true,
configurable: true,
enumerable: true
});
console.log(obj1.a); // 4
console.log(obj2.a); // 3
从上面的示例可以看出,在 obj1 对象本身上重新定义 a 属性后,再访问 obj1.a 时返回的是实例上的属性值 4,而 obj2 上的 a 属性的值仍然是 3。因为子对象中重新定义的属性会屏蔽原型链上的同名属性。
本文链接:http://task.lmcjl.com/news/8392.html