承接着上文 Vue 构造函数,完成 init.js 中 initState 对数据劫持的初始化方法
init.js
import proxyData from './proxy';import observe from './observe';function initState (vm) {var options = vm.$options;if (options.data) {initData(vm); // 针对 data}}function initData (vm) {var data = vm.$options.data;// 不直接使用用户 options 提供的 data// 如果是 options.data 是 function 就用 vm 为 this 来执行,否则就使用 options.data,|| {} 是保证如果 options 中没有 data 就是一个空的对象// 最后挂在 vm._data 上data = vm._data = typeof data === 'function' ? data.call(vm) : data || {};// 第一个数据劫持:数据代理,将 vm._data 挂到 vm 上for(var key in data) {proxyData(vm, '_data', key);}// 要对 data 和 data 内的对象和数组进行观察observe(data);}export {initState}
proxy.js 用于数据代理
function proxyData (vm, target, key) {Object.defineProperty(vm, key, {get () {return vm[target][key];},set (newValue) {vm[target][key] = newValue;}})}export default proxyData;
observe.js 观察对象
import Observer from './observer';function observe (data) {if (typeof data !== 'object' || data === null) return ;return new Observer(data);}export default observe;
observeArr.js 观察数组
import Observer from './observer';function observeArr (arr) {for (var i = 0; i < arr.length; i++) {observe(arr[i]);}}export default observeArr;
observer.js 观察者类
处理对象与数组的方法是不一样的
- {} defineProperty
- 让对象的每一个属性实现响应式
 
 - [] 自己去写方法
- 数组要更改原数组的方法,对于修改数组的方法也要自己重写
- 先建立 array.js 来处理关于数组
 - 把 data 的原型改为修改过的 arrMethods
 - 递归观察数组 ```javascript import defineReactiveData from ‘./reactive’; import { arrMethods } from ‘./array’; import observeArr from ‘./observeArr’;
 
 
 - 数组要更改原数组的方法,对于修改数组的方法也要自己重写
 
function Observer (data) { if (Array.isArray(data)) { data.protot = arrMethods; observeArr(data); } else { this.walk(data); } }
Observer.prototype.walk = function (data) { var keys = Object.keys(data);
for (var i = 0; i < keys.length; i ++) { var key = keys[i], value = data[key];
// 用于定义响应数据defineReactiveData(data, key, value); // 写在 reactive.js
} }
export default Observer;
<a name="h7okJ"></a># array.js 专门处理数组- 把专门修改数组的方法记录在 [config.js](#RPMUv)- 使用 Object.create 以原数组为原型创建新的对象 arrMethods- 为 arrMethods 重写每一个会修改数组的方法- 执行原数组的方法- 对要追加数组的这个新数组进行观察 [observeArr](#MHKZV)```javascriptimport { ARR_METHODS } from './config';import observeArr from './observeArr';var originArrMethods = Array.prototype,arrMethods = Object.create(originArrMethods); // 使用 Object.create 以原数组为原型创建新的对象ARR_METHODS.map(function(m) {// 重写每一个会修改数组的方法arrMethods[m] = function () {var args = Array.prototype.slice.call(arguments), // 使用数组的 slice 把类数组的 argumenmts 转为数组rt = originArrMethods[m].apply(this, args); // 执行原数组方法的行为// 不仅执行原数组方法的行为, 对要追加数组的这个新数组进行观察var newArr;switch (m) {case 'push':case 'unshift':newArr = args;break;case 'splice':newArr = args.slice(2);break;default;break;}newArr && observeArr(newArr);return rt;}});export {arrMethods}
reactive.js 专门处理响应式
value 有可能还是一个对象或数组,要再递归观察
- 需要递归 observe
 - 设置对象的 newValue 也可能是对象或数组,也要递归观察
```javascript
function defineReactiveData (data, key, value) {
  // 因为这个 value 有可能还是一个对象或数组所以要递归观察
observe(value);
Object.defineProperty(data, key, {
}, set(newValue) {get() {return value;
} }); }if (newValue === value) return;observe(newValue);value = newValue;
 
export default defineReactiveData;
<a name="RPMUv"></a># config.js 相关配置```javascriptvar ARR_METHODS = ['push','pop','shift','unshift','splice','sort','reverse'];export {ARR_METHODS}
