前端学习笔记:第一次使用Object.defineProperty

225 阅读2分钟

前言

之前看过别人的文章,知道Vue实现的核心是通过劫持Object.defineProperty,实现对data对象属性的监测,并根据data对象属性是否更新,来响应视图的变化。不过,一直都不知道这里的劫持是什么意思,这两天试了一下,记录一下自己的学习过程。

使用Object.defineProperty进行测试

在网上查Vue实现的资料,经常会看到这样一段代码:

let data = {
    name: "123"
}
let value = data.name;

Object.defineProperty(data, 'name', {
    get: function() {
        console.log("用户执行了读取data属性的操作")
        return value
    },
    set: function(newValue) {
        console.log("用户给data的属性重新进行了赋值")
        return newValue
    }
    
})

//以下代码用于在控制台测试
data.name = "1234"

setTimeout(function() {
    data.name = "12345"
}, 2000)

setTimeout(function() {
    data.name = "123456"
}, 4000)

先不管上面的代码是什么意思,我们在浏览器执行一下这段代码,看看打印的结果,结果如下。

测试结果猜测

上面的代码中,我们对data.name进行了三次赋值操作,控制台也打印了三次set函数的执行结果。这是不是说明,我们日常习以为常的赋值操纵,其实底层是通过Object.defineProperty这个函数来实现的呢?

翻一下《JS权威指南》,我们找到Object.defineProperty的相关知识点,发现果然如此。不过这本书对Object.defineProperty的介绍非常简单。这个结果并不能支持我们进一步了解Vue的实现原理,我们改造一下上文中的Object.defineProperty函数。

Object.defineProperty(data, 'name', {
    get: function() {
        console.log("用户执行了读取data属性的操作")
        return value
    },
    set: function(newValue) {
        console.log(newValue)
        console.log("用户给data的属性重新进行了赋值")
        return newValue
    }
    
})

然后我们再看看控制台打印出来的结果:

非常有趣的结果。原来在set函数中,我们就已经拿到了新的值。也就是说,假如这里的data.name是HTML页面中要显示的文本,我们只需要在set函数中判断value和newValue是否相等,就可以判断HTML的内容是否需要更新。

将数据更改和DOM绑定

为了更直观的展示,这里写一个最简单的HTML元素。

假如data.name要插入到这个div里
<div id="app></div>

为了完成div内容的更新,我们重新修改Object.defineProperty函数

function updateDOM(data) {
    let div = document.querySelector("#app");
    div.innerHTML = data
}

Object.defineProperty(data, 'name', {
    get: function() {
        console.log("用户执行了读取data属性的操作")
        return value
    },
    set: function(newValue) {
        console.log(newValue)
        console.log("用户给data的属性重新进行了赋值")
        updateDOM(newValue)
        return newValue
    }
    
})


我们在浏览器里看看结果,发现页面的div部分内容在2s后、4s后先后变成了12345、123456。这里我只修改了data.name的值,但是页面上div的内容也随之发生了改变。这样来看,我好像已经实现了一个最简单的响应式的数据更新?

结语

一次非常有意思的探究哦!