2020年11月20日
响应式原理(2)- 数组类型
数据data中包含数组类型,在进行响应式转换的过程中,会涉及到push新增的数据等操作,需将其转化为响应式数据。(以下示例为push方法)
在对方法进行拦截的一般处理办法:
- 1、使用一个临时的函数名存储函数
- 2、重新定义原来的函数
- 3、定义扩展功能
- 4、调用临时存的那个函数
// 1 function fn(){ console.log('原始的方法'); } let fun = fn; // 2 fn = function (){ // 4 fun(); // 3 console.log('扩展的方法'); } fn();
拦截数组的方法(示例的方法是push):修改原型链结构__proto__
- 1、定义数组的变量a
- 2、创建数组原型
- 3、重写的方法
- 4、调用临时变量a
let ARRAY_METHOD = ['push']; // 1 let arr = [] // 2 let array_methods = Object.create(Array.prototype); // 3 循环需扩展的数组方法名,并创建一个方法 ARRAY_METHOD.forEach(method => { array_methods[ method ] = function (){ console.log('调用拦截'); // 调用原有的方式 let res = Array.prototype[ method ].apply(this , arguments); return res; } }) // 4 arr.__proto__ = array_methods;
对数组类型进行响应式处理:需在Object.defineProperty中进行递归数据响应化方法reactify。以及在数组方法拦截中调用改方法进行数据push
var data = { name:'张三', age:12, code:[ {name:'语文'}, {name:'数学'} ] } // 数组方法拦截开始 let ARRAY_METHOD = ['push']; let array_methods = Object.create(Array.prototype); // 3 循环需扩展的数组方法名,并创建一个方法 ARRAY_METHOD.forEach(method => { array_methods[ method ] = function (){ console.log('调用拦截'); // 变为响应式数据 for(var i=0;i<arguments.length;i++){ reactify(arguments[i]) } // 调用原有的方式 let res = Array.prototype[ method ].apply(this , arguments); return res; } }) // 数组方法拦截结束 function defineReactive(target, key, value, enumerable){ if(typeof value === 'object' && value!= null && !Array.isArray(value)){ reactify(value); } Object.defineProperty(target, key, { configurable: true, enumerable: !!enumerable, set(newValue){ if(typeof newValue === 'object' && newValue!= null && !Array.isArray(newValue)){ reactify(newValue); }else if(Array.isArray(newValue)){ for(var i=0;i<newValue.length;i++){ reactify(newValue[i]); } } value = newValue; }, get(){ console.log(value) return value; } }) } function reactify(data){ let keys = Object.keys(data); for(var i=0;i<keys.length;i++){ let key = keys[i]; let val = data[key]; if(Array.isArray(val)){ // 数组类型 val.__proto__ = array_methods;//数组响应式方法调用 for(var j=0;j<val.length;j++){ reactify(val[j]); } }else{ // 引用类型 defineReactive(data, key, val, true); } } } reactify(data);