时间:2021-05-26
=与Object.defineProperty
为JavaScript对象新增或者修改属性,有两种不同方式:直接使用=赋值或者使用Object.defineProperty()定义。如下:
// 示例1var obj = {};// 直接使用=赋值obj.a = 1;// 使用Object.defineProperty定义Object.defineProperty(obj, "b",{ value: 2});console.log(obj) // 打印"{a: 1, b: 2}"这样看两者似乎没有区别,对吧?但是,如果使用Object.getOwnPropertyDescriptor()查看obj.a与obj.b的属性的描述描述符(property descriptor)时,会发现=与Object.defineProperty并不一样:
// 示例2var obj = {};obj.a = 1;Object.defineProperty(obj, "b",{ value: 2});console.log(Object.getOwnPropertyDescriptor(obj, "a")); // 打印"{value: 1, writable: true, enumerable: true, configurable: true}"console.log(Object.getOwnPropertyDescriptor(obj, "b")); // 打印"{value: 2, writable: false, enumerable: false, configurable: false}"可知,使用=赋值时,属性的属性描述符value是可以修改的,而writable、enumerable和configurable都为true。
而使用Object.defineProperty()定义的属性的属性描述符writable、enumerable和configurable默认值为false,但是都可以修改。对于writable、enumerable和configurable的含义,从名字就不难猜中,后文也会详细介绍。
使用=赋值,等价于使用Object.defineProperty()定义时,同时将writable、enumerable和configurable设为true。代码示例3和4是等价的:
// 示例3var obj = {};obj.name = "Fundebug";console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}// 示例4var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: true, enumerable: true, configurable: true});console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}Object.defineProperty()
使用Object.defineProperty()定义时若只定义value,则writable、enumerable和configurable默认值为false。代码示例5和6是等价的:
// 示例5var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug"});console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}// 示例6var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: false, enumerable: false, configurable: false});console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}由于writable、enumerable和configurable都是false,导致obj.name属性不能赋值、不能遍历而且不能删除:
// 示例7var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug"});// writable为false,无法赋值obj.name = "云麒";console.log(obj.name); // 打印"Fundebug"// enumerable为false,无法遍历console.log(Object.keys(obj)); // 打印"[]"// configurable为false,无法删除delete obj.name;console.log(obj.name); // 打印"Fundebug"若在严格模式(“use strict”)下,示例7中的代码会报错,下文可见。
writable
writable为false时,属性不能再次赋值,严格模式下会报错“Cannot assign to read only property”
// 示例8"use strict"var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: false, enumerable: true, configurable: true});obj.name = "云麒"; // 报错“Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'”writable为true时,属性可以赋值,这一点读者不妨自行测试。
enumerable
enumerable为false时,属性不能遍历:
// 示例9"use strict"var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: true, enumerable: false, configurable: true});console.log(Object.keys(obj)) // 打印"[]"enumerable为true时,属性可以遍历,这一点读者不妨自行测试。
configurable
enumerable为false时,属性不能删除,严格模式下会报错“Cannot delete property”:
// 示例10"use strict"var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: true, enumerable: true, configurable: false});delete obj.name // 报错“Uncaught TypeError: Cannot delete property 'name' of #<Object>”enumerable为true时,属性可以删除,这一点读者不妨自行测试。
writable与configurable
当writable与enumerable同时为false时,属性不能重新使用Object.defineProperty()定义,严格模式下会报错“Cannot redefine property”:
// 示例11"use strict"var obj = {};Object.defineProperty(obj, "name",{ value: "Fundebug", writable: false, configurable: false})Object.defineProperty(obj, "name",{ value: "云麒"}) // 报错“Uncaught TypeError: Cannot redefine property: name”当writable或者enumerable为true时,属性可以重新使用Object.defineProperty()定义,这一点读者不妨自行测试。
本文所有代码示例都在Chrome 67上测试。
参考
Object.defineProperty()
Object.getOwnPropertyDescriptor()
StackOverflow: Why can't I redefine a property in a Javascript object?
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
定义(Definition).定义属性需要使用相应的函数,比如:Object.defineProperty(obj,"prop",propDesc)如果obj没
在javascript中,对象的属性分为数据属性和存储器属性两种:两种属性的区别我们使用Object.defineProperty()先来直观的感受一下这两者的
Object.defineProperty这个方法了不起啊,vue.js是通过它实现双向绑定的。。而且Object.observe也被草案发起人撤回了。。所以d
下面通过代码给大家介绍vue属性拦截实现双向绑定,具体代码如下所示:letobj={}letget=''Object.defineProperty(obj,'g
菜菜:“老大,那个,Object.defineProperty是什么鬼?”假设我们有个对象user;我们要给它增加一个属性name,我们会这么做varuser=