关键词

JavaScript对象属性设置和屏蔽技巧

关于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

展开阅读全文