<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> // vue2对象响应式原理 Object.defineProperty() // vue2数组响应式原理 覆盖可以修改数组的7个方法 // 从数组原型中获取这7个方法,并覆盖为可以发送更新通知的函数实现 const originalProto = Array.prototype // 克隆数组原型,复制新的原型对象 const arrayProto = Object.create(originalProto) const meArr = ['push','pop','shift','unshift','splice','reverse','sort'] meArr.forEach( method => { // 做原型数组方法做的事情 arrayProto[method] = function(){ originalProto[method].apply(this,arguments) // 通知更新 notifyUpdate() } } ) // 思想: 递归遍历传入obj,定义每个属性的拦截 function observe(obj){ if(typeof obj !== 'object' || obj == null){ return } // 判断类型,如果是数组就替换他的原型 if(Array.isArray(obj)){ Object.setPrototypeOf(obj,arrayProto) }else{ // 拿出对象的key值 const keys = Object.keys(obj) for (let index = 0; index < keys.length; index++) { const key = keys[index]; // 对obj的每个数据进行拦截 defineReactive(obj,key,obj[key]) } } } // 具体定义指定的key拦截器 function defineReactive(obj,key,val){ // 递归遍历 observe(val) // val实际上是一个闭包 Object.defineProperty(obj,key,{ get(){ return val }, set(newVal){ if(newVal !== val){ observe(newVal) notifyUpdate() val = newVal } } }) } function notifyUpdate(){ console.log('页面更新'); } const data = {foo:'foo',bar:{a:1},arr:[1,2,3]} observe(data) // 1普通更新 // data.foo = 'foooooooo' // 2嵌套对象更新 // data.bar.a = 10 // 3直接赋值对象 // data.bar = {a:10} // 数组更新 data.arr.push(4) // vue2的问题分析 // 1需要响应的数据较大时,递归遍历性能不好,消耗较大 // 2新增或删除属性无法监听 // 3数组响应化需要额外实现,导致语法有限制,如数组length无法操作数组,通过$set等方法实现 </script> </body> </html>