赞
踩
Vue响应式原理之Object.defineProperty,通俗易懂好兄弟快学起来
首先是对对象的监听,话不多说先看代码
let obj = { a: { b: 1, c: 2 }, d: 4 } observe(obj) obj.a.b = 3 //直接修改b的值 监听成功 obj.a = 4 //把a赋值成基本类型 监听成功 obj.d = 5 //直接修改d的值 监听成功 obj.d = { //把d修改成对象 监听成功 e: 8 } console.log(obj.d) function observe(target){ // 不是对象或者数组直接返回 if(typeof target !== 'object' || target === null) return target for(let key in target){ // 遍历 defineProperty(target, key, target[key]) } } function defineProperty(target, key, value){ //监听函数 observe(value) //当value也为对象时进行递归深度监听 例如上面定义的obj.a Object.defineProperty(target, key, { get(){ return value }, set(newValue){ if(newValue !== value){ update(value, newValue) value = newValue observe(newValue) //当新值赋值为对象时, 对该对象进行监听 } } }) } function update(oldValue ,newValue){ //模拟更新操作 console.log(`oldValue: ${oldValue}, newValue: ${newValue}`) }
接下来是对数组的监听,其中有一个问题就是方法的返回值需要重写,这里只提供监听的思路
let arrPrototype = Array.prototype const arrProto = Object.create(arrPrototype); // 该方法创建新对象,隐式原型原型指向arrPrototype,扩展新的方法时不会影响原型 // 简单举几个方法 ['push', 'pop', 'shift', 'unshift', 'splice'].forEach((methodName) => { arrProto[methodName] = function() { console.log(this) arrPrototype[methodName].call(this, ...arguments) } }) let obj = { a: { b: 1, c: 2 }, d: 4, y: [1, 2, 4, 3, 8] } observe(obj) obj.y.push(2, 3) console.log(obj.y.length) function observe(target){ // 不是对象或者数组直接返回 if(typeof target !== 'object' || target === null) return target if(Array.isArray(target)){ target.__proto__ = arrProto //如果target为数组则改变原型指向,使用重写后的方法 } for(let key in target){ // 遍历 defineProperty(target, key, target[key]) /* console.log(key) */ } } function defineProperty(target, key, value){ //监听函数 observe(value) //当value也为对象时进行递归深度监听 例如上面定义的obj.a Object.defineProperty(target, key, { get(){ return value }, set(newValue){ if(newValue !== value){ update(value, newValue) value = newValue observe(newValue) //当新值赋值为对象时, 对该对象进行监听 } } }) } function update(oldValue ,newValue){ //模拟更新操作 console.log(`oldValue: ${oldValue}, newValue: ${newValue}`) }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。