[JS]属性标志和属性描述符

到目前为止,属性对我们来说只是一个简单的“键值”对。但对象属性实际上是更灵活且更强大的东西。
 
对象属性(properties),除 value 外,还有三个特殊的特性(attributes),也就是所谓的“标志”:

    writable — 如果为 true,则值可以被修改,否则它是只可读的。
    enumerable — 如果为 true,则会被在循环中列出,否则不会被列出。
    configurable — 如果为 true,则此属性可以被删除,这些属性也可以被修改,否则不可以。

    我们用“常用的方式”创建一个属性时,它们都为 true。
 
 
 
Object.getOwnPropertyDescriptor 方法允许查询有关属性的完整信息。
1 let user = {
2 name: 'jack'
3 }
4 console.log( Object.getOwnPropertyDescriptor(user, 'name') ) 
5 // {value: "jack", writable: true, enumerable: true, configurable: true}

 

 

为了修改标志,我们可以使用 Object.defineProperty,如果该属性不存在,则会根据标志和给定的值创建该属性。
Object.defineProperty(obj, propertyName, descriptor)
 1 let user = {
 2   name: 'jack'
 3 }
 4 
 5 Object.defineProperty(user, 'name', {
 6   value: 'lily',
 7   writable: false
 8 })
 9 
10 console.log(Object.getOwnPropertyDescriptor(user, 'name')) 
11 // {value: "lily", writable: false, enumerable: true, configurable: true}
12 
13 
14 Object.defineProperty(user, 'age', {
15   value: 20
16 })
17 
18 console.log(Object.getOwnPropertyDescriptor(user, 'age')) 
19 // {value: 20, writable: false, enumerable: false, configurable: false}
20 // 如果没有提供标志,默认都是false
21 
22 user.age = 18 // 该属性不会被修改,并且严格模式下会报错
23 console.log(user) // {name: "lily", age: 20}
24 
25 for (let i in user) {
26   console.log(i) // name  属性 age 不会出现,因为它的标志 enumerable 为 false
27 }

 

 

不可配置标志(configurable:false)
不可配置性对 defineProperty 施加了一些限制:

     不能修改 configurable 标志。
     不能修改 enumerable 标志。
     不能将 writable: false 修改为 true(反之亦然)。
     不能修改访问者属性的 get/set(但是如果没有可以分配它们)。


    configurable: false 的思想是防止更改属性标志或删除属性标志,而不是更改它的值。
    不可配置但可写的属性的值是可以被更改的。
1 delete user.age
2 
3 console.log(user) // {name: "lily", age: 20}
4 
5 Object.defineProperty(user, 'age', { // Error
6 writable: true
7 })

 

 

Object.defineProperties(obj, descriptors),允许一次定义多个属性。
1 Object.defineProperties(user, {
2   city: { value: '成都', writable: true },
3   province: { value: '四川', writable: true }
4 })
5 
6 console.log(user) // {name: "lily", age: 20, city: "成都", province: "四川"}

 

 

通常我们克隆一个对象是通过赋值的方式来复制,但这样并不能复制标志
如果需要复制标志,我们可以使用 Object.getOwnPropertyDescriptors(obj) 方法。
它与 Object.defineProperties 一起可以用作克隆对象的标志:
 1 let person = {}
 2 Object.defineProperties(person, {
 3   name: {
 4     value: 'john',
 5     writable: true,
 6     enumerable: false,
 7     configurable: true
 8   },
 9   age: {
10     value: 22,
11     writable: false,
12     enumerable: true
13   }
14 })
15 
16 let clone = Object.defineProperties({}, Object
17   .getOwnPropertyDescriptors(person))
18 
19 console.log(clone) // {age: 22, name: "john"}
20 console.log(Object.getOwnPropertyDescriptors(clone))
21 /*
22 name: {value: "john", writable: true, enumerable: false, configurable: true}
23 age: {value: 22, writable: false, enumerable: true, configurable: false}
24 */

 

 

posted @ 2020-03-10 10:07  冯风风  阅读(259)  评论(0编辑  收藏  举报