Object.defineProperty对数组的监听

对象的属性分为:数据属性和访问器属性。如果要修改对象的默认特性,必须使用Object.defineProperty方法,它接收三个参数:属性所在的对象、属性的名字、一个描述符对象。那么接下来先看看他如何深度监听原生数组的~~~~~~

observer

//先准备数据

const data = {

    name:'zhangsan',

    age:20,

    info:{

       address: '北京' // 需要深度监听

    },

    nums:[10, 20, 30]

}


1.     [endif]其中的info需要深度监听 其次定义一个方法,这个方法判断了这个不是对象或数组 然后重新定义各个属性(for in 也可以遍历数组)

2.     [endif]其次重新定义属性 监听起来并且运用到了刚刚封装的监听方法 和核心API,( 注意,value 一直在闭包中,value

=newValue此处设置完之后,再 get 时也是会获取最新的值)

3.     [endif]其次监听原生数组方法, 原理就是重写数组的七个原始方法,当使用者执行这些方法时,我们就可以监听到数据的变化,然后做些跟新操作

完整代码流程

// 触发更新视图

function updateView() {

   console.log('视图更新')

}

// 重新定义数组原型   监听原生数组方法

constoldArrayProperty = Array.prototype

// 创建新对象,原型指向oldArrayProperty ,再扩展新的方法不会影响原型

const arrProto =Object.create(oldArrayProperty);

['push', 'pop', 'shift', 'unshift', 'splice', sort,reverser].forEach(methodName => {

   arrProto[methodName] = function () {

       updateView() //触发视图更新

//执行原始操作

       oldArrayProperty[methodName].call(this, ...arguments)

       // Array.prototype.push.call(this, ...arguments)  //执行原始操作

    }

})

// 重新定义属性,监听起来

function defineReactive(target, key, value) {

    //深度监听

   observer(value)

    //核心API

   Object.defineProperty(target, key, {

       get() {

           return value

       },

       set(newValue) {

           if (newValue !== value) {

               //深度监听

                observer(newValue)

               //设置新值

         //注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值

               value = newValue

               //触发更新视图

               updateView()

           }

        }

    })

}


// 监听对象属性

function observer(target) {

    if(typeof target !== 'object' || target === null) {

       //不是对象或数组

       return target

    }

    if(Array.isArray(target)) {

       target.__proto__ = arrProto

    }

    //重新定义各个属性(for in 也可以遍历数组)

    for(let key in target) {

       defineReactive(target, key, target[key])

    }

}

// 准备数据

const data = {

    name:'zhangsan',

    age:20,

    info:{

       address: '北京' // 需要深度监听

    },

    nums:[10, 20, 30]

}

// data.name = 'lisi'

// data.age = 21

// // console.log('age', data.age)

// data.x = '100' // 新增属性,监听不到 —— 所以有Vue.set

// delete data.name // 删除属性,监听不到 —— 所有已Vue.delete

// data.info.address = '上海' // 深度监听

data.nums.push(4) // 监听数组

其实我们发现 observer 其实是个递归,最后会把所有的数据都变成响应式

总结

可以感觉到,在用Object.defineProperty实现数据响应式时我们必须要遍历所有的数据,还需要重写数组的方法,性能消耗也比较大,我们知道Vue2.x就是基于Object.defineProperty实现数据响应式的但新版本的Vue3放弃了Object.defineProperty采用Proxy重写了响应式系统,那Vue3为什么要选择Proxy?Proxy又是如何实现数据拦截的呢?,我们下期分享用Proxy如何实现响应式。

你可能感兴趣的:(Object.defineProperty对数组的监听)