在讲到Obeject.defineProperty()方法以前先得说明一下ECMAScript中有两种属性:数据属性和访问器属性。 javascript
两种属性存在的意义:描述对象属性(key)的一些特性,由于这些属性是内部值,通常放到 [[两个中括号]] 中。vue
Object.defineProperty(obj , 'key' , {描述信息,是个对象,相似配置项} ) 方法接收三个参数,属性所在的对象,属性名 和一个描述符对象。java
数据属性的描述符是下面的一个或者多个(configurable、enumerable、writable 和 value)数组
访问器属性的描述符是如下的一个或多个(configurable、enumerable、get 和 set)框架
经过 Object.defineProperty()
方法,能够建立数据属性(并设定其内部属性),也能够建立访问器属性(访问器属性包含 getter
和 setter
函数)函数
数据属性的各项解释:spa
enumerable : 可枚举性,是否能经过for-in或者Object.keys来遍历prototype
writable : 可修改(可写入),是否能修改value属性值3d
value : 属性的属性值 (读出和写入都是从这里读出和保存的),默认undefined 数据属性是能够直接经过 对象.属性obj.key
的形式访问和赋值的双向绑定
configurable : 是否可配置,当它为false的时候,一、上面三项的true和false值都不能改变了,二、对象自己也不能经过delete来删除三、数据属性和访问器属性也不能来回转化了
访问器属性的各项解释:
configurable 、enumerable同上
get : 读取属性的时候调用,默认值undefined
set : 设置属性的时候调用,默认值undefined
对比数据属性和访问器属性的属性异同
数据属性做用: 修改属性默认的特性 (会新建出数据属性)
访问器的做用: 访问和设置数据属性的属性值,不会建立出 .
一、对象属性的建立对比----- 这里建立的是数据属性不是访问器属性,访问器属性只有一种建立方式
A、字面量建立对象的形式:var obj = {key : value } ------ var person1 = {age : 3} 直接建立了age属性和属性值
B、Object.defineProperty(obj ,'key' {...} )建立对象 ------ var person2 = {}; Object.defineProperty(person2, "age", { value: 3 });
经过统一的操做 :
① console.log(person1 .name) ② person1.age = 4 ③ console.log(person1 .name) 得出 // 3 , 4 赋给了新的值
① console.log(person2 .name) ② person2.age = 4 ③ console.log(person2 .name) 得出 // 3 , 3 赋值没有成功
原理:
直接在对象上定义的属性var obj = {key : value }(字面量形式和new Object()形式
) ,它们的Configurable、Enumerable 和Writable特性都被设置为 true,而Value特性被设置为指定的值
经过 Object.defineProperty()定义的属性 它们的Configurable、Enumerable 和Writable特性都被设置为 false,而Value特性被设置为指定的值,这时候的属性值是只读的
二、重点:数据属性不只能够直接访问和设置(对象.属性/obj.key的形式),也能够经过定义的访问器(getter setter)来专门访问和设置。
得出结论:
① 经过发现book下面并无真正的year属性,证实了数据属性并不能根据访问器属性来定义建立,访问器属性只是操做访问器属性,这个属性能够理解为是在get和set这一动态读取和设置的过程当中发挥做用。
② set
和get
是一对勾子(hook)函数,要理解触发机制(是根据调用book.year或者设置book.year=2005这个时间点触发的,因此这个year能够随便取值):就是访问器属性在调用时,实际上对应触发访问器属性中定义的 get
方法(最后返回的值是其中return出来的结果),当对一个对象的某个属性赋值时,则会自动触发调用相应的set
函数。(若是不了解运行机制,须要打断点走一遍便可)
③ book只有_year和edtion两个数据属性(是否是数据属性,要看带不带value属性),year不是数据属性(访问属性不包含数据值,也不会显式的写出来),可是可是book.hasOwnProperty("year");
确实返回 true
。说明了访问器属性也属于对象本身添加的属性。只是读写方式和普通的不同。
三、再来撸一遍代码,看看运行的原理具体是怎样的??
四、怎么区分数据属性仍是访问器属性???看里面的描述符对象。二者是不能混用的。
五、js中的属性的理解:
javascript中一共有三种属性:
普通属性:也就是常规的数据属性,这种属性是用户来添加修改等,把它设置成什么样,就返回出来什么样,不会作些额外的事情。 var obj ={name : "yang"};那么console.log(obj.name) //yang
内部属性:好比数组arr的length属性,函数的prototype属性,DOM节点的innerHTML属性,用户赋完值之后,取值的时候,不必定按预期,有时候还会额外的作一些事情,也难以改变他们的行为。
好比说某一数组,它的长度为10, 当咱们设置它为11时,它就会增长一个undefined元素,再设置为9时,就会从后面删掉两个元素。
函数的prototype若是被改变,至关于将其父类改变了,会new不一样类型的实例。
DOM的innerHTML,咱们赋值时是一个字符串,再取出时,这字符串可能会与原来的不同, 而且在原元素上生成了不同的子节点。
访问器属性,容许用户在赋值或取值都通过预先设定的函数,从而实现内部属性的那一种特殊效果。
六、应用(能够代替对象中的getter和setter函数)
==
其余地方:vue框架MVVM的数据双向绑定,数据的实时观察,不一样于angular使用的脏检查。
七、和Object.defineProperty()相关的一些对象方法。
obj.propertyIsEnumerable('key')
obj.hasOwnProperty('key') 能够检测出访问器属性
Obeject.getOwnpropertyDescriptor(obj , 'key') 或者描述符对象 ----- 有就返回对象,不然是undefined。
Object.keys(obj)方法,遍历key值 。 当Object.defineProperty()中enumerable为false的时候,是遍历不出来的。
八、其余
Obeject.prototype的configurable是false,表明不可配置
对象obj的toString方法是原型链上的是不可枚举的 obj.propertyIsEnumerable(toString') // false
最后:不要再IE8 及之前版本 中使用 Object.defineProperty()