先看这一段代码
// 拿到数组的原型const oldArrayProperty = Array.prototype// 创建一个新的对象,原型指向oldArrayProperty,这么做为的是不污染全局的Array原型// Object.create 和 new Objcet() 的区别在知识库 前端知识点中有const arrProto = Object.create(oldArrayProperty)// 给arrProto增加方法,例如pusharrProto.push = function() {updateView() //这里触发更新视图Array.prototype.push.call(this, ..arguments) // 这里才是真正执行push方法}
然后修改1-4中的代码
/* 模拟更新视图 -- 这个不变 */function updateView() {console.log('视图更新')}
const oldArrayPrototype = Array.prototyoeconst arrProto = Object.create(oldArrayPrototype)// 这里没写全所有的数组方法!!['push', 'pop', 'shift', 'unshift', 'splice', 'slice'].forEach(methodName => {arrProto[methodName] = function() {updateView() // 更新视图oldArrayPrototype[methodName].call(this, ...arguments)}})/* 监听对象属性 */function observer(target) {// 只监听对象和数组if (typeof target !== 'object' || target == null) {return target}// 对数组进行特殊处理// 这样,操作target是数组的时候,就是使用的是我们自定义的方法了if(Array.isArray(target)) {target.__proto__ = arrProto}// 重新定义各个属性for (let key in target) {defineReactive(target, key, target[key])}}
/* 对属性重新定义,并且监听 -- 这个也不变 */function defineReactive(target, key, val) {// 深度监听observer(val) // 因为val不一定是值,也可能是一个对象或数组Object.defineProperty(target, key, {get() {return val},set(newVal) {if (newVal !== val) {// 深度监听 新增加的如果是对象和数组也要加入监听observer(newVal)// 设置新值val = newVal}// 更新视图updateView()}})}
