1 // 触发更新视图 2 function updateView() { 3 console.log('视图更新') 4 } 5 6 // 重新定义数组原型 7 const oldArrayProperty = Array.prototype 8 // 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型 9 const arrProto = Object.create(oldArrayProperty); 10 ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => { 11 arrProto[methodName] = function () { 12 updateView() // 触发视图更新 13 oldArrayProperty[methodName].call(this, ...arguments) 14 // Array.prototype.push.call(this, ...arguments) 15 } 16 }) 17 18 // 重新定义属性,监听起来 19 function defineReactive(target, key, value) { 20 // 深度监听 21 observer(value) 22 23 // 核心 API 24 Object.defineProperty(target, key, { 25 get() { 26 return value 27 }, 28 set(newValue) { 29 if (newValue !== value) { 30 // 深度监听 31 observer(newValue) 32 33 // 设置新值 34 // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值 35 value = newValue 36 37 // 触发更新视图 38 updateView() 39 } 40 } 41 }) 42 } 43 44 // 监听对象属性 45 function observer(target) { 46 if (typeof target !== 'object' || target === null) { 47 // 不是对象或数组 48 return target 49 } 50 51 // 污染全局的 Array 原型 52 // Array.prototype.push = function () { 53 // updateView() 54 // ... 55 // } 56 57 if (Array.isArray(target)) { 58 target.__proto__ = arrProto 59 } 60 61 // 重新定义各个属性(for in 也可以遍历数组) 62 for (let key in target) { 63 defineReactive(target, key, target[key]) 64 } 65 } 66 67 // 准备数据 68 const data = { 69 name: 'zhangsan', 70 age: 20, 71 info: { 72 address: '北京' // 需要深度监听 73 }, 74 nums: [10, 20, 30] 75 } 76 77 // 监听数据 78 observer(data) 79 80 // 测试 81 // data.name = 'lisi' 82 // data.age = 21 83 // // console.log('age', data.age) 84 // data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set 85 // delete data.name // 删除属性,监听不到 —— 所有已 Vue.delete 86 // data.info.address = '上海' // 深度监听 87 data.nums.push(4) // 监听数组