前言
之前看过别人的文章,知道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的内容也随之发生了改变。这样来看,我好像已经实现了一个最简单的响应式的数据更新?
结语
一次非常有意思的探究哦!