# 彻底搞懂对象的数据属性描述符、存储属性描述符 ## 属性描述符 ```js let obj = { name: "ziu", age: 18 } Object.defineProperty(obj, "height", { value: 1.88 }) console.log(obj) // { name: 'ziu', age: 18 } ``` `obj`对象的控制台输出中,并没有`defineProperty`新定义的`height`,这是因为不可枚举的(不可遍历的),在打印时并没有和其他属性一起输出。这个属性已经被添加到对象中,只不过不可见。 ```js console.log(obj.height) // 1.88 ``` 属性描述符是一个对象,根据功能不同,可以分为两类:**数据属性描述符**和**存储属性描述符** ### 数据属性描述符 * 数据属性描述符(Data Properties) * `value`该属性对应的值,默认`undefined` * `configurable`该属性描述符是否可被改变、是否可被删除,默认为`false` * `enumerable`该属性是否可被枚举,默认为`false` * `writable`该属性是否可以被写入新的值,默认为`false` **没有用属性描述符定义的对象属性(直接使用`.`语法)**,也是具有以上属性描述符的特性的,`value`值为属性被赋值的值,其他`configurable`、`emumerable`、`writable`默认值都为`true`。**注意,属性描述符区全为小写。** ```js let obj = { name: "ziu", age: 18 } // 数据属性描述符 Object.defineProperty(obj, "address", { value: "Beijing", // 该属性对应的值,默认为undefine configurable: false, // 该属性描述符是否可被改变、是否可被删除,默认为false enumerable: true, // 该属性是否可被枚举,默认为false writable: true // 该属性是否可以被写入新的值,默认为false }) // configurable delete obj.address obj.address = "Shanghai" console.log(obj.address) // Beijing // enumerable console.log(obj) for(let key in obj) { console.log(key) } console.log(Object.keys(obj)) // writable obj.address = "Tianjin" console.log(obj.address) ``` ### 存储属性描述符 * 存储属性描述符(Accessor Properties) * `get`当访问该属性时,会调用此函数,默认为`undefined`。 * `set`当属性值被修改时,会调用此函数,默认为`undefined`。 注意,`get`、`set`描述符与`vaule`、`writable`描述符不共存。 | | `configurable` | `enumerable` | `value` | `writable` | `get` | `set` | | ---------- | -------------- | ------------ | ---------- | ---------- | ---------- | ---------- | | 数据描述符 | 可以 | 可以 | 可以 | 可以 | **不可以** | **不可以** | | 存取描述符 | 可以 | 可以 | **不可以** | **不可以** | 可以 | 可以 | ```js let obj = { name: "ziu", age: 18, _address: "Beijing" } // Accessor Properties Object.defineProperty(obj, "address", { enumerable: true, configurable: true, // value: "Beijing", // writable: true, get: function() { return this._address }, set: function(val) { this._address = val } }) console.log(obj.address) // 调用getter() Beijing obj.address = "Shanghai" // 调用setter() console.log(obj._address) // Shanghai ``` ### 应用场景 1. 隐藏某个私有属性,希望直接被外界使用和赋值。(下划线开头的变量一般为私有属性) 2. 获取某个属性被访问或赋值的时刻,可以设置伴随被访问或被赋值时,执行其他函数。 ```js Object.defineProperty(obj, "address", { get: function() { bar() return this._address }, set: function(val) { foo() this._address = val } }) console.log(obj.address) // got address value once obj.address = "Shanghai" // resetted address value once function bar() { console.log("got address value once") } function foo() { console.log("resetted address value once") } ```