# $set、$delete原理
# $set原理
$set内部调用的是Vue.set (opens new window)方法,它是在initGlobalAPI (opens new window)时,给Vue添加的全局静态方法。我们将源码进行简化,方便理解。
- target是数组,我们调用target.splice方法来修改数组。注意,此时数组对象在observe (opens new window)阶段,splice方法已经被重写了。此时调用splice时,会触发数组的
dep.notify,通知页面更新。 - target是一个对象
- 如果对象中本来就有这个key(并且不是对象原型上的key),直接设置值并返回即可。如果对象是响应式,设置值时,视图默认就会更新。
- 获取对象的observe实例: _ ob_ 。
- 注意,在observe阶段,每个对象都有一个dep,并且对象上都有一个 _ ob_ 属性,指向其对象的observe实例。
- 如果_ ob_ 不存在,说明它不是一个响应式对象。直接设置值并返回即可。
- 给对象通过defineReactive方法,添加响应式时,并通过
dep.notify()通知视图更新。
export function set (target: Array<any> | Object, key: any, val: any): any {
// 1、target是数组,且key是一个有效的下标
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
// 在索引key位置,通过splice方法添加数据(数组的splice方法已经被重写了)
target.splice(key, 1, val)
return val
}
// 如果target中已经存在该key,直接返回。如果对象是响应式时,视图默认就会更新
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
// 获取target的Observer实例对象:__ob__
const ob = (target: any).__ob__;
if (!ob) { // 说明target不是一个响应式对象,直接设置值即可,页面也不会更新
target[key] = val
return val
}
// 2) target是一个对象,调用defineReactive,将新添加的key变为响应式对象
defineReactive(ob.value, key, val)
// ob.dep,即targe对象自己的那个dep实例,触发更新,重新渲染页面
ob.dep.notify()
return val
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# $delete原理
$set内部调用的是Vue.del (opens new window)方法,它是在initGlobalAPI (opens new window)时,给Vue添加的全局静态方法。整个过程与$set类型,可参考代码注释。
function del (target: Array<any> | Object, key: any) {
// 1、target是数组,且key是一个有效的下标
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 在索引key位置,通过splice方法删除数据(数组的splice方法已经被重写了)
target.splice(key, 1)
return
}
const ob = (target: any).__ob__
// 如果对象没有这个属性,直接返回
if (!hasOwn(target, key)) {
return
}
// 如果是对象,直接删除target.key,并调用dep.notify更新视图
delete target[key]
if (!ob) {
return
}
ob.dep.notify()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19