Vue源码学习(一):数据劫持(对象类型)

发布时间 2023-08-31 22:29:10作者: 养肥胖虎

好家伙,了解一下Vue如何实现数据劫持

 

1.Vue中data的使用

首先,我得搞清楚这玩意的概念,我们先从vue的使用开始吧

想想看,我们平时是如何使用vue的data部分的?

无非是这两种情况

(你可千万不要带着惊讶的表情说"啊!原来有两种写法的吗")

//函数写法
data() {
    return {
        msg: "I like beef"
    }
}
//对象写法 data:{ return { msg: "I like beef" } }

 像这样:

 

2.那么什么是数据劫持?

对属性的读取和修改拦截

简单来说就是数据的任何变化都要能监测到,这样才能根据数据变化做对应操作

就像"劫持"这个词的意思"抢过里来,盯着"

 

3.为什么要用数据劫持?

Vue2最好用的部分----响应式数据,数据一经更改,页面上的数据就会进行局部更新

如果不进行数据劫持,不知道数据状态就无法更新数据

 

4.如何实现数据劫持

然后我们开始思考,数据劫持是从什么时候开始的?

在 Vue 中,数据劫持是在创建 Vue 实例时完成的

具体来说,当你实例化一个 Vue 对象时,Vue 会通过使用 Object.defineProperty() 方法来劫持(或称为监听)对象的属性,以便在属性被访问或修改时能够执行相应的操作。

Vue 的数据劫持是通过将数据对象传递给一个称为“响应式系统”的函数来实现的。

这个函数会遍历数据对象的所有属性,并为每个属性设置 getter 和 setter。

当我们获取或修改这些属性时,getter 和 setter 会触发对应的操作,以实现数据的响应式更新。

 

5.代码部分:

(并非源码,这是一个例子)

//对对象中的属性进行劫持
function defineReactive(data, key, value) {
    Object.defineProperty(data, key, {
        get() {
            // console.log('获取')
            return value
        },
        set(newValue) {
            // console.log('设置')
            if (newValue == value) {
                return;
            }
            value = newValue
        }
    })

}

 

关于defineProperty()方法:Object.defineProperty() - JavaScript | MDN (mozilla.org)

这是一个简化版的数据劫持示例。

这个 defineReactive() 函数接受一个数据对象 `data`、一个属性名 `key` 和初始值 `value`,并使用 Object.defineProperty() 方法定义了一个 getter 和一个 setter。

在 getter 中,当获取属性值时,会返回存储在 `value` 变量中的当前值。

在 setter 中,当尝试设置属性值时,会将新值存储在 `value` 变量中,

这个 defineReactive() 函数可以用于对对象中的某个属性进行劫持,使得在对该属性进行访问或修改时能够触发相应的操作。

 

完整的例子:

export function observer(data) {
    // console.log(data)

    //判断数据
    if (typeof data != 'object' || data == null) {
        return data
    }
    //对象通过一个类
    return new Observer(data)
}

class Observer {
    constructor(value) {
        Object.defineProperty(value, "__ob__", {
            enumerable: false,
            value: this
        })
        //判断数据
        // console.log(value)
        if (Array.isArray(value)) {
            //value.__proto__ = ArrayMethods
            // console.log("shuzhu")
            //如果你是数组对象
            //this.observeArray(value)
        } else {
            this.walk(value)
        }
    }
    walk(data) {
        let keys = Object.keys(data)
        for (let i = 0; i < keys.length; i++) {

            //对象我们的每个属性进行劫持
            let key = keys[i]
            let value = data[key]
            defineReactive(data, key, value)
        }

    }
    observeArray(value) { //[{a:1}]
        for (let i = 0; i < value.length; i++) {
            observer(value[i])
        }
    }
}
//对对象中的属性进行劫持
function defineReactive(data, key, value) {
    observer(value) //深度代理
    Object.defineProperty(data, key, {
        get() {
            // console.log('获取')
            return value
        },
        set(newValue) {
            // console.log('设置')
            if (newValue == value) {
                return;
            }
            observer(newValue)
            value = newValue
        }
    })

}

 

 深度代理明天更...