Vue.js 源码中,Vue.delete 和 vm.$delete 指向的是同一个函数,两者作用完全相同,其中,vm.$delete 是 Vue.delete 的别名。
Vue.delete用来删除对象的属性。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到属性被删除的限制,但是你应该很少会使用它。需要注意的是,目标对象不能是一个 Vue 实例或 Vue 实例的根数据对象。
也可以使用这个方法来删除数组中的元素。
该方法接收两个参数:
-
{Object | Array} target目标对象/目标数组 -
{string | number} key/index要删除的对象键名/要删除的数组元素索引
那要实现一个功能相同的 myDelete 方法的话,其实只要将对象中的属性删除之后,通知视图更新,即执行收集的依赖即可。那么:
function myDelete(obj, key) {
delete obj[key]
target()
}
这里通过调用 target 来执行依赖通知视图更新,target 是前面写的帮助中转依赖的一个全局变量。可以这么写是因为我到现在一直是使用之前写的 render 方法来做测试,没有别的依赖,而且只调用了一次 myWatch 方法,也没有收集别的依赖,所以这里也先通过调用 target() 来实现通知视图更新的功能。这样做肯定会有很多问题,但这些问题都需要依赖 Dep 类来解决,所以也放到 Dep 类之后再写。
这个方法实现了删除对象属性,但还不能删除数组元素,故增加以下代码:
function myDelete(obj, key) {
if (Array.isArray(obj) && isValidArrayIndex(key)) {
obj.splice(key, 1)
return
}
delete obj[key]
target()
}
如果检测到传进来的 obj 是数组,并且 key 是个有效的数组索引,那么使用 splice 方法直接将 key 位置上的数组元素删除即可,变异方法 splice 本身已经可以触发响应,所以删除之后 return 即可。其中,isValidArrayIndex 方法是 Vue数据响应原理(五)—— 实现Vue.set 中已经封装好的方法。
将 myDelete 方法和前面文章中的代码放在一起,经过测试,功能是没有问题的。但同样,还要兼容异常与边界情况:
如果要删除的 key 不是 obj 自身的属性的话,那直接 return 就好了,什么也不用做。顺便封装一个 hasOwn 方法:
const hasOwnProperty = Object.prototype.hasOwnProperty
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key)
}
不直接使用 obj.hasOwnProperty(key) 而去调 Object 原型上的 hasOwnProperty 方法是因为传进来的 obj 是不受控制的,obj 上可能会有重新定义过的 hasOwnProperty 方法。
这时,增加以下判断:
function myDelete(obj, key) {
if (Array.isArray(obj) && isValidArrayIndex(key)) {
obj.splice(key, 1)
return
}
if (!hasOwn(obj, key)) {
return
}
delete obj[key]
target()
}
即最终代码。







网友评论