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

vue,源码,学习,数据,劫持,对象,类型 · 浏览次数 : 74

小编点评

**了解 Vue 中数据劫持** **1. Vue 中 data 的使用** - `data` 是一个对象,用于存储数据的存储。 - `data` 可以使用函数或对象编写。 **2. 数据劫持** - 数据劫持是指将数据对象的所有属性进行劫持,以便在数据变化时触发相应的操作。 - 数据劫持可以用于实现数据的响应式更新,即当数据变化时页面上的数据就会进行局部更新。 **3. 为什么要用数据劫持?** - Vue2 中的响应式数据更新效率更高,因为当数据更改时页面只进行局部更新,而不是整个页面重新渲染。 - 数据劫持可以优化应用程序性能,因为它可以避免频繁的页面渲染。 **4. 实现数据劫持** - 通过使用 `Object.defineProperty()` 方法创建 getter 和 setter。 - getter 和 setter 用于在数据获取或修改时触发相应的操作。 **5. 代码示例** ```javascript export function observer(data) { // 遍历数据对象的所有属性 let keys = Object.keys(data) // 对每个属性进行劫持 for (let i = 0; i < keys.length; i++) { let key = keys[i] let value = data[key] // 定义 getter 和 setter defineReactive(data, key, value) } } ``` **6. 深入代理** - 当数据是数组对象时,`Object.defineProperty()` 会设置 `__proto__` 属性,使其成为数组对象。 - 遍历数组对象的所有属性,并使用 `defineReactive()` 将它们劫持。

正文

好家伙,了解一下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
        }
    })

}

 

 深度代理明天更...

 

与Vue源码学习(一):数据劫持(对象类型)相似的内容:

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

好家伙,了解一下Vue如何实现数据劫持 1.Vue中data的使用 首先,我得搞清楚这玩意的概念,我们先从vue的使用开始吧 想想看,我们平时是如何使用vue的data部分的? 无非是这两种情况 (你可千万不要带着惊讶的表情说"啊!原来有两种写法的吗") //函数写法 data() { return

Vue源码学习(十):关于dep和watcher使用的一些思考

好家伙, 前面想了好久,都没想明白为什么要dep和watcher打配合才能实现数据-视图同步 为什么要多一个依赖管理这样的东西 给每个数据绑个watcher(xxfunction),然后,数据变了,调set,然后调xxfunction,不就行了, 然后今天突然想明白了,不是为什么要这么干,而是必须这

Vue源码学习(十一):计算属性computed初步学习

好家伙, 1.Computed实现原理 if (opts.computed) { initComputed(vm,opts.computed); } function initComputed(vm, computed) { // 存放计算属性的watcher const watchers = vm

Vue源码学习(二):渲染第一步,模板解析

好家伙, 1.去哪了 在正式内容之前,我们来思考一个问题, 当我们使用vue开发页面时,中的内容是如何变成我们网页中的内容的? 它会经历四步: 解析模板:Vue会解析中的内容,识别出其中的指令、插值表达式({{}}),以及其他元素和属性。

Vue源码学习(三):渲染第二步,创建ast语法树

好家伙,书接上回 在上一篇Vue源码学习(二):渲染第一步,模板解析中,我们完成了模板解析 现在我们继续,将模板解析的转换为ast语法树 1.前情提要 代码已开源https://github.com/Fattiger4399/analytic-vue.git手动调试一遍, 胜过我

Vue源码学习(四):渲染第三步,将ast语法树转换为渲染函数

好家伙, Vue源码学习(三):渲染第二步,创建ast语法树, 在上一篇,我们已经成功将 我们的模板 转换为ast语法树 接下来我们继续进行操作 1.方法封装 由于代码太多,为了增加代码的可阅读性 我们先将代码进行封装 index.js import { generate } f

Vue源码学习(六):(支线)渲染函数中with(),call()的使用以及一些思考

好家伙, 昨天,在学习vue源码的过程中,看到了这个玩意 嘶,看不太懂,研究一下 1.上下文 这段出现vue模板编译的虚拟node部分 export function renderMixin(Vue) { Vue.prototype._c = function () { //创建标签 return

Vue源码学习(五):渲染第四步,生成虚拟dom并将其转换为真实dom

好家伙, 前情提要: 在上一篇我们已经成功将ast语法树转换为渲染函数 现在我们继续 1.项目目录 代码已开源https://github.com/Fattiger4399/analytic-vue.git手动调试一遍, 胜过我解释给你听一万遍 新增文件:vnode/index.js vnode/p

Vue源码学习(七):合并生命周期(混入Vue.Mixin)

好家伙, 1.使用场景 现在来,来想一下,作为一个使用Vue的开发者,假设现在我们要使用created(),我们会如何使用 1.1. .vue文件中使用 {{ message }}

Vue源码学习(九):响应式前置:实现对象的依赖收集(dep和watcher)

好家伙,这是目前为止最绕的一章,也是十分抽象的一章 由于实在太过抽象,我只能用一个不那么抽象的实例去说服我自己 完整代码已开源https://github.com/Fattiger4399/analytic-vue.git 1.我们要做什么? 来看这个例子, index.html setTimeou