github源码
html
Object.defineProperty()方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。 vueJS采用 ES5 提供的 Object.defineProperty() 方法,监控对数据的操做,从而能够自动触发数据同步。而且,因为是在不一样的数据上触发同步,能够精确的将变动发送给绑定的视图,而不是对全部的数据都执行一次检测。
首先咱们得先知道,ECMAScript中有两种属性:数据属性和访问器属性( ie8如下只能在dom对象上使用;不能使用在普通对象上)vue
[[Configurable]]: 表示可否修改属性。默认值为true [[Enumerable]]: 表示属性是否可枚举,也就是是否能够经过for-in循环返回属性。默认值为true [[Writable]]: 表示可否修改属性的值。默认值为true [[value]]: 包含这个属性的值.读取属性的时候就是经过这里开始读。默认值为undefined
[[Configurable]]: 表示可否修改属性。默认值为true [[Enumerable]]: 表示属性是否可枚举,也就是是否能够经过for-in循环返回属性。默认值为true [[Get]]: 在读取属性时调用的函数,默认时undefined [[Set]]: 在设置属性时调用的函数,默认时undefined 咱们要是想修改默认属性的值就可使用:Object.defineProperty(obj,prop,descriptor);
var a= {} Object.defineProperty(a,"b",{ value:123 }); console.log(a.b);//123
第一个参数obj:目标对象a 第二个参数prop:须要定义的属性或方法的名字"b" 第二个参数descriptor:目标属性所拥有的特性
value:属性的值 writable:若是为false,属性的值就不能被重写,只能为只读了 configurable:总开关,一旦为false,就不能再设置他的(value,writable,configurable) enumerable:是否能在for...in循环中遍历出来或在Object.keys中列举出来。 get:后面介绍 set:后面介绍 注意:在 descriptor 中不能同时设置访问器(get 和 set)和 wriable 或 value,不然会错,就是说用 get 和 set,就不能用 writable 或 value 中的任何一个 在基本用法里只设置了value,没有设置别的,能够简单的理解为(暂时这样理解)它会默认帮咱们把writable,configurable,enumerable。都设上值,并且值还都是false。(仅限于第一次设置的时候),等同于如下代码: var a = {}; Object.defineProperty(a, 'b', { value: 123, writable: false, enumerable: false, configurable: false }); console.log(a.b); //123
总开关,第一次设置 false 以后,,第二次什么设置也不行了: 也就是说,你可使用Object.defineProperty()方法无限修改同一个属性,可是当把configurable改成false以后就有限制了 var a = {}; Object.defineProperty(a, 'b', { configurable: false }); Object.defineProperty(a, 'b',{ configurable: true }); //报错:Uncaught TypeError: Cannot redefine property: b(…)
var a = {}; Object.defineProperty(a, 'b', { value: 123, writable: false //只读 }); console.log(a.b); // 打印 123 a.b = 124; // 没有错误抛出(在严格模式下会抛出,即便以前已经有相同的值) console.log(a.b); // 打印 123, 赋值不起做用。
var a = {} Object.defineProperty(a,"b",{ value:3445, enumerable:true }); console.log(Object.keys(a));// 打印["b"] //改为false: var a = {} Object.defineProperty(a,"b",{ value:3445, enumerable:false }); console.log(Object.keys(a));// 打印[]
访问器属性不能直接定义!只能经过Object.defineProperty()来定义: var a= {} Object.defineProperty(a,"b",{ set:function(newValue){ console.log("赋值是:"+newValue) }, get:function(){ console.log("取值:") return 2 //注意这里,我硬编码返回2 } }); a.b =1; //赋值是: 1 console.log(a.b) ; //取值 2 简单来讲,这个 b 赋值或者取值的时候会分别触发 set 和 get 对应的函数
//判断是否是对象 function isObj(obj){ var type = Object.prototype.toString.call(obj); return type === '[object Object]'; } //执行函数: function objFun(obj){ if(isObj(obj)){ new Observer(obj); } } function Observer(obj){ this.data = obj; this.walk(obj); } //监听事件函数: Observer.prototype.walk = function(obj){ for(var k in obj){ def(obj,k,obj[k]) } } function def(obj,k,val){ Object.defineProperty(obj,k,{ configurable:true, enumerable:true, get:function(){ console.log('get取值'); return val; }, set:function(newVal){ if(val === newVal){ return; } val = newVal; console.log('set设置值') } }); } //测试: var obj = {a:111,b:222}; objFun(obj); console.log(obj.a)//get取值 222 obj.a = 333;//set设置值 console.log(obj)
html: <div> Object.defineProperty实现数据和视图的联动: <br> <span id="nickName"></span> <div id="introduce"></div> </div> js:(视图控制器) var userInfo = {}; Object.defineProperty(userInfo,'nickName',{ get:function(){ return document.getElementById('nickName').innerHTML; }, set:function(nick){ document.getElementById('nickName').innerHTML = nick } }); Object.defineProperty(userInfo,'introduce',{ get:function(){ return document.getElementById('introduce').innerHTML; }, set:function(introduce){ document.getElementById('introduce').innerHTML = introduce } }); //console.log(userInfo) userInfo.nickName = '我是nickName'; userInfo.introduce = '我是introduce' 上面设置userInfo的nickName属性时会调用set方法,更新DOM节点的HTML
Vue双向绑定的实现原理系列(一):Object.defineproperty
Vue双向绑定的实现原理系列(二):设计模式
Vue双向绑定的实现原理系列(三):监听器Observer和订阅者Watcher
Vue双向绑定的实现原理系列(四):补充指令解析器compilegit