vue双向绑定原理之Object.defineProperty的应用

    技术2022-07-10  196

    众所周知,vue2.0的双向数据绑定使用es6的Object.defineProperty方法实现的,本文我讲会为大家仔细讲解之间的实现原理。

    Object.defineProperty() 法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 这个方法接收三个参数, Object.defineProperty(obj, prop, desc) obj 需要定义属性的当前对象.prop 当前需要定义的属性名.desc 属性描述符(configurable, enumerable, writable, set, get)

    其实我们平时给对象添加属性例如

    let obj = {}; obj.name = 'lisi';

    用Object.defineProperty()的话就是

    var o = {}; Object.defineProperty(o, 'name', { enumerable: true,// 可被枚举, 就是for in 循环能得到key configurable: true, // 能够被改变,能够被删除。 writable: true, // 可被赋值改变 value: "list" })

    在我们的vue中其实就是利用Object.defineProperty中的get和set方法,获取对象的值的时候会触发get方法,设置值的时候会触发set方法,从而去通知订阅的对象达到响应式。注意: 设置了get,set 就不能设置writable属性了否则会报错。

    var o = {}; var value = ''; Object.defineProperty(o, 'name', { enumerable: true, configurable: true, // writable: true, get() { return value }, set(newValue) { value = newValue; } })

    了解了上面Object.defineProperty()的基本用法,我们来模仿vue中对数据的劫持。

    <!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> var obj = { name: 'yumang', age: 18, girls: ['美女'] }; function defineReactive(o, key, value){ if (typeof value === 'object' && value != null && !Array.isArray(value)) { // 是非数组的引用类型 reactify(value); // 递归 } Object.defineProperty(o, key ,{ configurable:true, enumerable:true, get(){ // get 的时候做额外操作 console.log('这里在获取'+ key + '的值') return value }, set(newValue){ // set 的时候做额外操作 console.log('这里在设置' + key + '的值'+ newValue) value = newValue; }, }) } /** * o 要被劫持的对象 * **/ function reactify (o){ let keys = Object.keys(o); for (let i=0; i< keys.length; i++ ){ let key = keys[i]; let value = o[key]; /** * 1. 数组监听 * 2. 对象和普通值的监听 * **/ if (Array.isArray(value)){ // 如果是数组 就要对数组里面的每一个属性进行监听 for(let j = 0; j< value.length; j ++) { if (typeof value[j] === 'object') reactify(value[j]) // 递归 } }else { // 对象和普通值的监听, 进入defineReactive的时候 如果对象里面还有对象就需要使用递归 defineReactive(o, key, value) } } } reactify(obj) </script> </body> </html>

    以上两个函数的递归调用我们就完成了对象属性的监听, 然而对于数组, 它的一些方法push等,却没有监听到,vue里面是怎么处理的呢。 我们下次再一起学习。

    Processed: 0.017, SQL: 9