使用Object.defineProperty重新定义属性时需要注意的一点

使用Object.defineProperty重新定义属性时需要注意的一点,具体说来:

当一个对象已存在某属性,重新定义该属性(如果允许)时,若未指定属性描述器的enumerable或configurable,则其默认值为原有属性描述器的对应的enumerable或configurable值。

TL;DR?

再次定义一个对象的属性时,新属性描述器中未指定的enumerable或configurable其默认值将由原属性描述器提供,而不再是false。

看来长话短说不了,依旧这么长,那就不废话了,举例说明:

设有一对象foo

var foo={
    firstName: "Foo",
    lastName: "Bar",
    get fullName(){
        return this.firstName+" "+this.lastName;
    }
};

//#test1
console.log(foo.fullName);
//"Foo Bar"

现需对foo进行升级

实现:
1. 支持middleName;
2. 在JSON.stringify(foo)时属性fullName不被序列化;

Object.defineProperty(foo,"fullName",{
    configurable:true,
    get: function(){
        var fullName=this.firstName;
        if(this.middleName)
            fullName+=" "+this.middleName;
        fullName+=" "+this.lastName;
        return fullName;
    }
});

//#test2
foo.middleName="Tim";
console.log(foo.fullName);
//"Foo Tim Bar"

//#test3
console.log(JSON.stringify(foo));
//{"firstName":"Foo","lastName":"Bar","fullName":"Foo Tim Bar","middleName":"Tim"}

升级后存在bug

从#test3的输出结果可以看出:JSON.stringify(foo)时属性fullName仍被序列化了。

于是检查fullName的属性描述器

console.log(Object.getOwnPropertyDescriptor(foo,"fullName"));
//{get: function fullName(){...}, set:undefined, enumerable:true, configurable:true}

发现enumerable值仍然是true,未指定应该是false才对呀。

是不是浏览器有bug?

换了个浏览器,亦存在同样问题。

浏览器没有错,机制如此而已

只好显式指定enumerable,打补丁修复现有问题。

(function(){
    var descriptor=Object.getOwnPropertyDescriptor(foo,"fullName");
    descriptor.enumerable=false;
    Object.defineProperty(foo,"fullName",descriptor);
})();

//#test4
console.log(JSON.stringify(foo));
//{"firstName":"Foo","lastName":"Bar","middleName":"Ent"}

总算搞定了,坑爹呀!

所以说,使用Object.defineProperty重新定义属性时需要注意

你可能感兴趣的:(使用Object.defineProperty重新定义属性时需要注意的一点)