JavaScript中对象的属性分为俩种:数据属性、访问器属性。
1.数据属性
数据属性包括四个特性(可称为属性描述符):
- Value:数据属性才有的专门读写属性值的位置,默认值为undefined
- Writable:表示属性的值是否可以被修改,默认为true
- enumberable:表示属性是否可以被遍历(通过for-in循环返回),默认值为true
- Configurable:表示属性是否可以配置(delete删除并重新定义、修改特性、改为访问器属性),默认为true
给一个对象显示的添加属性后,value设置为属性指定的值,其余三个属性描述符默认为true
object.defineProperty()是JavaScript提供用来修改属性默认特性的方法,它接受三个参数(object,'属性名','描述特性的对象')其中描述特性的对象可以包含以上四个任意特性的一个或多个,示例如下:
1 let person = {}; 2 Object.defineProperty(person, "name", { 3 value: "郑大侠", //设置person对象的name属性的值为'郑大侠' 4 writable: false, //设置name属性的值不可修改 5 }); 6 console.log(person.name); //郑大侠 7 person.name = "zxf"; 8 console.log(person.name); //郑大侠
- 值得注意的是configurable若设置为false,则该属性不能从对象上删除了,非严格模式下调用delete无效,严格模式下则会出错。此外,若属性的configurable特性设置为不可配置后,则不能再变回了,此后,除writable外,其余特性被修改都会报错。
- 调用object.defineProperty()时,configurable,enumberable,writable的值如果没有设置,则都默认设置为false.
2.访问器属性
访问器属性比较特殊,不包括数据值,但包含获取函数getter和设置函数setter,这俩个函数不是必须的。
每当读取访问器属性时,就会调用(触发)获取函数getter,其作用就是返回一个有效的值;
在写入访问器属性时则会调用(触发)设置函数setter,这个函数决定对数据做出什么样的修改。
访问器属性同样包括四个属性描述符:
- configurable:表示属性是否可以配置(delete删除并重新定义、修改特性、改为数据属性),默认为true
- enumberable:表示属性是否可以被遍历(通过for-in循环返回),默认值为true
- get:获取函数,在读取属性时调用,默认值为undefined
- set:设置函数,在写入属性时调用,默认值为undefined
与数据属性不同,访问器属性开发时并不常用,是不能直接定义的,必须使用Object.defineProperty()
1 // 定义一个对象并赋予俩个数据属性 2 let book = { 3 year_: 2017, 4 edition: 1, 5 }; 6 7 // 给book对象定义一个访问器属性:newYear 8 Object.defineProperty(book, "newYear", { 9 get: function (newValue) { 10 return this.year_; 11 }, 12 set: function (newValue) { 13 if (newValue > 2017) { 14 this.year_ = newValue; 15 this.edition += newValue - 2017; 16 } 17 }, 18 }); 19 book.newYear = 2021; //写入访问器属性时调用set函数使得book.year_ = 2021,book.edition = 5 20 console.log(book.edition); //5
以上是访问器属性典型的使用场景:设置一个属性值会导致一些其他变化的发生。我想,这便是Vue实现双向绑定以及响应式原理追踪数据变化的实现手段来源。通过object.defineProperty() 方法和访问器属性。
ps:另外我学到这里,有时看到getter与setter函数 ,到处找不到它们的定义,暂时将其理解为get:function(){}中具体的function(),get指向getter函数;setter同理。以后不对再来改
定义多个属性的方法Object.defineProperties():Object.defineProperties(要为其添加或修改属性的对象,{属性与其描述符的对象})如下:
1 let book = {}; 2 // 一次性定义多个属性以及其属性描述符 3 Object.defineProperties(book, { 4 name: { value: "雪中悍刀行" }, 5 year_: { value: 2011 }, 6 edition: { value: 1 }, 7 newYear: { 8 get() { 9 return this.year_; 10 }, 11 set(newValue) { 12 if (newValue > 2011) { 13 this.year_ = newValue; 14 this.edition += newValue - 2011; 15 } 16 }, 17 }, 18 }); //第二个参数为属性与其描述符组成的对象。
另有读取属性的属性描述符(特性)的方法Object.getOwnPropertyDescriptor():接受俩个参数:属性所在的对象、要取得的其描述符的属性。返回值是一个对象。
对于普通数据属性返回Value,Writable,enumberable ,configurable四个属性描述符组成的对象;
对于访问器属性返回configurable,enumberable,get,set四个属性描述符组成的对象。
1 let book = {}; 2 // 一次性定义多个属性以及其属性描述符 3 Object.defineProperties(book, { 4 name: { value: "雪中悍刀行" }, 5 year_: { value: 2011 }, 6 edition: { value: 1 }, 7 newYear: { 8 get() { 9 return this.year_; 10 }, 11 set(newValue) { 12 if (newValue > 2011) { 13 this.year_ = newValue; 14 this.edition += newValue - 2011; 15 } 16 }, 17 }, 18 }); 19 let descriptor_year_ = Object.getOwnPropertyDescriptor(book,"year_");//descriptor_year_接收数据属性year_的描述符对象 20 console.log(descriptor_year_); 21 let descriptor_newYear = Object.getOwnPropertyDescriptor(book,"newYear");//descriptor_newYear接受访问器属性newYear的描述符对象 22 console.log(descriptor_newYear);
另有Object.getOwnPropertyDescriptors()方法,只接受一个对象 ,它会分别获得该对象所有属性的所有属性描述符,并返回一个对象,该对象由其中每个属性与其属性描述符对象共同组成。
对上述对象输出console.log(Object.getOwnPropertyDescriptors(book));