Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的
JavaScript
对象。而当你修改它们时,视图会进行更新。
当你把javascript对象传给vue实例的data属性的时候,Vue 将遍历此对象全部的属性,经过 Object.defineProperty
来给每一个属性都添加 getter
和 setter
.javascript
而每一个组件实例又都有一个watcher
对象,它会将组件渲染过程当中的属性渲染为【依赖】,当数据发生变化的时候,会触发setter
,会通知 watcher
从新计算,从而导致它关联的组件得以更新。vue
Object.defineProperty()
方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。java
Object.defineProperty(obj, prop, descriptor)
参数函数
obj
须要定义属性的对象。prop
需被定义或修改的属性名。descriptor
需被定义或修改的属性的描述符。Object.defineProperty(obj, "key", { enumerable: false, // 不可枚举 configurable: false, // 不可更改 writable: false, // 不可被赋值运算符改变 value: "static" }) // 建立属性 var o = {}; Object.defineProperty(o, 'a', { enumerable: true, configurable: true, writable: true, value: 17 }); // 对象o拥有了属性a,值为17 var bValue = 38; Object.defineProperty(o, 'b', { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; }, enumerable: true, configurable: true }); o.b; // 38
var o = {}; // 建立一个新对象 Object.defineProperty(o, "a", { value : 37, writable : false }); console.log(o.a); // 打印 37 o.a = 25; // 没有错误抛出(在严格模式下会抛出,即便以前已经有相同的值) console.log(o.a); // 打印 37, 赋值不起做用。
var o = {}; Object.defineProperty(o, "a", { value : 1, enumerable:true }); Object.defineProperty(o, "b", { value : 2, enumerable:false }); Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false o.d = 4; // 若是使用直接赋值的方式建立对象的属性,则这个属性的enumerable为true for (var i in o) { console.log(i); } // 打印 'a' 和 'd' (in undefined order) Object.keys(o); // ["a", "d"] o.propertyIsEnumerable('a'); // true o.propertyIsEnumerable('b'); // false o.propertyIsEnumerable('c'); // false
configurable
特性表示对象的属性是否能够被删除,以及除 writable 特性外的其余特性是否能够被修改。this
Object.defineProperty(person,'a',{ configurable:false,//为false的时候不容许修改默认属性了 }) =============================== # 改成false以后再试试修改其余属性 Object.defineProperty(person,'a',{ configurable:true, enumerable:true, writable:true, value:1 }) //woa,控制台直接报错了!连想把false值改回true都不行!也就是说,这个改动是一次性了! //也就是说,你可使用Object.defineProperty()方法无限修改同一个属性,可是当把configurable改成false以后就有限制了
1 、首先定义一个cb函数,这个函数用来模拟试图更新。code
// function cb (val) { /* 渲染视图 */ console.log("视图更新啦~"); }
二、 定义一个defineReactive ,这个方法经过 Object.defineProperty
来实现对对象的「响应式」化,入参是一个 obj(须要绑定的对象)
、key(obj的某一个属性)
,val(具体的值)
。server
function defineReactive(obj, key, val){ Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function(){ return val; }, set:function(newVal) { if (newVal === val) return; cb(newVal); } }) } // 当一个对象,赋值给Vue实力的data选项的时候,就会触发该操做,对数据进行响应化处理
三、 固然这是不够的,咱们须要在上面再封装一层 observer 。这个函数传入一个 value(须要「响应式」化的对象),经过遍历全部属性的方式对该对象的每个属性都经过 defineReactive 处理
。对象
function observer(val) { if(!val || typeof val != 'object') { return ; } Object.keys(val).forEach((key)=> { defineReactive(val,key, val[key]); }) }
四、 在 Vue 的构造函数中,对 options 的 data 进行处理ip
class Vue { /* Vue构造类 */ constructor(options) { this._data = options.data; observer(this._data); } }
五、 这样咱们只要 new 一个 Vue 对象,就会将 data 中的数据进行「响应式」化。若是咱们对 data 的属性进行下面的操做,就会触发 cb 方法更新视图。get