vm.$delete
vm.$delete
的作用是删除数据中的某个属性。由于Vue.js
的变化侦测是使用Object.defineproperty
实现的,所以数据是使用delete
关键字删除的,那么无法发现数据发生了变化。为了解决这个问题,Vue.js
提供了vm.$delete
方法来删除数据中的某个属性,并且此时Vue.js
可以侦测到数据发生了变化。
1. 用法
vm.$delete(target,key)
- 参数
- {
Object
|Array
} target - {
string
|number
} key/index
- {
- 用法:
删除对象的属性。如果对象是响应式的,需要确保删除能触发视图更新。这个方法主要用于避开Vue.js
不能检测到属性被删除的限制。
目标对象不能是Vue.js
实例或Vue.js
实例的根对象数据。
2. 实现原理
vm.$delete
方法是为了解决变化侦测的缺陷。 它帮助我们在删除属性后自动向依赖发送消息,通知Watcher
数据发生了变化。
在Vue.js
的原型上挂载$.delete
方法:
import { del } from '../observer/index'
Vue.prototype.$delete = del;
del
函数:
export function del(target,key){
const ob = target.__ob__;
delete target[key];
ob.dep.notify();
}
处理遇到数组的情况:
export function del(target,key){
if(Array.isArray(target) && isValidArrayIndex(key)){
target.splice(key,1)
return
}
const ob = target.__ob__;
delete target[key];
ob.dep.notify();
}
数组的处理逻辑和vm.$set
差不多。因为只需要处理删除的情况,所以只需要使用splice
将参数key
所指定的索引位置的元素删除。因为使用了splice
方法,数组拦截器会自动向依赖发送通知。
与vm.$set
一样,vm.$delete
也不可以在Vue.js
实例或Vue.js
实例的根数据对象上使用。
export function del(target,key){
if(Array.isArray(target) && isValidArrayIndex(key)){
target.splice(key,1);
return;
}
const ob = target.__ob__;
// 新增
if(target._isVue || {ob && ob.vmCount}){
process.env.NODE_ENV !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
)
return;
}
delete target[key];
ob.dep.notify();
}
新增代码解读:如果target
上有_isVue
属性(target
是Vue.js
实例)或者ob.vmCount
数量大于1(target
是根数据),则直接返回,终止程序继续执行,并且如果是开发环境,会在控制台发出警告。
如果删除的这个key
不是target
自身的属性,就什么都不做,直接退出程序执行:
export function del(target,key){
if(Array.isArray(target) && isValidArrayIndex(key)){
target.splice(key,1);
return;
}
const on = target.__ob__;
if(target._isVue || {ob && ob.vmCount}){
process.env.NODE_ENV !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
)
return;
}
// 如果key不是target自身的属性,则终止程序继续执行
if(!hasOwn(target,key)){
return;
}
delete target[key];
ob.dep.notify();
}
如果删除的这个key
在target
中不存在,不需要执行删除操作,也不需要向依赖发送通知。
判断target
是不是一个响应式数据,也就是说判断target
上存不存在__ob__
属性。只有响应式数据才会发送通知,非响应式数据只需要执行删除操作即可。
如果数据不是响应式的,则使用return
语句阻止执行发生通知的语句:
export function del(target,key){
if(Array.isArray(target) && isvalidArrayIndex(key)){
target.splice(key,1);
return;
}
const on = target.__ob__;
if(target.isVue || {ob && observable.vmCount}){
process.env.NODE_ENV !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
)
return;
}
if(!hasOwn(target,key)){
return;
}
delete target[key];
// 如果ob不存在,则直接终止程序
if(!obj){
return;
}
ob.dep.notify();
}
在删除属性后判断ob
是否存在,如果不存在,则直接终止程序,继续执行下面发送变化通知的代码。