专栏名称: 前端外刊评论
最新、最前沿的前端资讯,最有深入、最干前端相关的技术译文。
目录
相关文章推荐
前端早读课  ·  【第3520期】Slack、Notion ... ·  昨天  
前端早读课  ·  【图书】MCP原理与实战:高效AI ... ·  昨天  
脚本之家  ·  大厂都在用的 12 大主流 AI ... ·  昨天  
脚本之家  ·  大厂都在用的 12 大主流 AI ... ·  昨天  
51好读  ›  专栏  ›  前端外刊评论

Vue.set 的副作用

前端外刊评论  · 公众号  · 前端  · 2020-03-18 08:30

正文

请到「今天看啥」查看全文


>
< p > {{ JSON.stringify(this.testObj) }} p >
< button @ click = "set('a')" > 设置testObj属性a button >
< button @ click = "set('b')" > 设置testObj属性b button >
div >

< script >
new Vue({
el : '#app' ,
data : {
testObj : {},
},
watch : {
'testObj.a' () {
alert( 'a' )
},
'testObj.b' () {
alert( 'b' )
},
},
methods : {
set (val) {
Vue.set( this .testObj, val, true );
}
},
})
script >
body >
html >

答案是:

点a的时候alert a,点b的时候alert b。

如果再接着点a,点b,提示什么?

答案是:

没有提示。

先总结一下发现的现象:用Vue.set为对象o添加属性,如果添加的属性是一个对象,那么o的所有属性会被触发响应。

是不是不明白?且请听我讲解一下。

要回答上面这些问题,我们首先需要理解一下Vue的响应式原理。 从Vue官网这幅图上我们可以看出:当我们访问data里某个数据属性p时,会通过getter将这个属性对应的Watcher加入该属性的依赖列表;当我们修改属性p的值时,通过setter通知p依赖的Watcher触发相应的回调函数,从而让虚拟节点重新渲染。

所以响不响应关键是看依赖列表有没有这个属性的watcher。

为了把依赖列表和实际的数据结构联系起来,我画出了vue响应式的主要数据结构,箭头表示它们之间的包含关系: Vue里的依赖就是一个Dep对象,它内部有一个subs数组,这个数组里每个元素都是一个Watcher,分别对应对象的每个属性。Dep对象里的这个subs数组就是依赖列表。

从图中我们可以看到这个Dep对象来自于__ob__对象的dep属性,这个__ob__对象又是怎么来的呢?这就是我们new Vue对象时候Vue初始化做的工作了。Vue初始化最重要的工作就是让对象的每个属性成为响应式,具体则是通过observe函数对每个属性调用下面的defineReactive来完成的:

/**
* Define a reactive property on an Object.
*/

function defineReactive (
obj,
key,
val,
customSetter,
shallow
)
{
var dep = new Dep();

var property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return
}

// cater for pre-defined getter/setters
var getter = property && property.get;
if






请到「今天看啥」查看全文