(1).Object.defineProperty
该方法是Object对象定义属性的方法,能够修改属性默认的特性javascript
/*参数解释: obj表示目标对象,即属性所在的对像; key表示属性名; 最后一个参数表示属性的描述符对象 */ Object.defineProperty(obj, key, { configurable: false, //属性是否能够被删除或修改,默认为false enumerable: false, //属性是否可枚举,默认为false writeable: true, //属性的值可否修改,默认为true value: 'yayaya', //包含该属性的数据值 get: function() {}, //获取属性的方法 set: function() {} //设置属性的方法 })
(2).观察者模式(发布-订阅)
(3).举例解析双向绑定
<1>.响应式基本原理
例1:
基本思路:渲染视图 <=监听每一个data的数据变化 <=遍历data中的每一项 <=获取数据html
html中代码: <!DOCTYPE html> <html> <head> <title>demo</title> </head> <body> <div id="demo"> </body> </html> <script type="text/javascript" src="vue2.js"></script> <script> //new 一个 Vue 对象,就会将 data 中的数据进行「 响应式」化 var v = new Vue({ el: '#demo', data: { name: '123' }, }) v._data.name = '456'; </script>
vue2.js中代码:vue
function Vue(options) { //获取数据 this._data = options.data; observe(this._data); } function observe(value) { //遍历data中的每一项 //先不考虑value为数组的复杂状况 if (!value || typeof value !== 'object') return; Object.keys(value).forEach(function(propertyName) { defineReactive(value, propertyName, value[propertyName]) }) } function defineReactive(obj, key, val) { //监听每一个data的数据变化 console.log('defineReactive==parameter', obj, key, val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, set: function(newVal) { console.log('newVal', newVal); if (val == newVal) return; update(); //若是新修改的值和原来的值不一样就从新渲染页面 }, get: function() { return val; } }) } function update() { console.log("update view===") }
输出结果:java
小结:从data到视图view的响应式原理主要用到的是Object.definePorperty对数据进行劫持,再更新视图数组
<2>.依赖收集
1>为何要有依赖收集this
例1: var globalData = { name: 'yayaya', age: '26' } var vue1 = new Vue({ data: { name: globalData.name } }) var vue2 = new Vue({ data: { name: globalData.name } })
假如咱们修改了globalData中name的值,那么vue1和vue2实例中用到全局name的地方都须要更新,这个时候就须要依赖收集,告诉观察者哪些实例下的数据须要更新.spa
2>.依赖收集的实现过程双向绑定
1.订阅者Dep:Dep的主要做用是存放Watcher观察者对象 function Dep() { //添加观察者watcher this.subs = []; this.addSub = function(sub) { this.subs.push(sub); console.log("sub==", sub); } //通知Watcher更新视图 this.notify = function() { this.subs.forEach(function(s) { s.update() }); } } Dep.target = null; 2.观察者Watcher:主要做用是监听数据变化更新视图 function Watcher() { Dep.target = this; //在new 一个Watcher 对象时将该对象赋值给Dep.target,在get 中会用到 this.update = function() { console.log('updata view===') } } 3.在defineReactivez和Vue中实现依赖收集 function defineReactive(obj, key, val) { //监听data中的数据变化 var dep = new Dep();//实例化一个订阅者 Object.defineProperty(obj, key, { enumerable: true, configurable: true, set: function(newVal) { //在set时发送通知给Watcher,从新渲染视图 console.log("set start==="); if (val == newVal) return; dep.notify(); //若是新修改的值和原来的值不一样就从新渲染页面 }, get: function() { //get时添加依赖 console.log("get start==="); dep.addSub(Dep.target); //把watcher实例添加到依赖中 return val; } }) } function Vue(options) { //获取数据 this._data = options.data; observe(this._data); new Watcher(); console.log("this._data.name", this._data.name) } function observe(value) { //遍历data中的每一项 //先不考虑value为数组的复杂状况 if (!value || typeof value !== 'object') return; Object.keys(value).forEach(function(propertyName) { defineReactive(value, propertyName, value[propertyName]) }) } 4.组件中的代码 var v = new Vue({ el: '#demo', data: { name: '123' }, }) console.log("name is changing") v._data.name = '456';
输出结果:code
小结:
首先vue在observe中注册并调用get,在get中,将Watcher实例经过addSub方法添加到dep的subs数组中,这完成了依赖添加的过程; 当数据变化时,调用Object.defineProperty中的set方法,判断数据是否发生改变,若是改变了,就调用dep中的notify方法通知Watcher,Watcher知道数据变化更新数据.htm