深入浅出Vue.js----变化侦测相关的API实现原理----vm.$delete

一、作用

(1)vm.$delete的作用是删除数据中个某个属性

(2)由于Vue.js的变化侦测是使用Object.defineProperty实现的,所以如果数据使用delete关键字删除的,那么无法发现数据发生了变化。

(3)为了解决这个问题,Vue.js提供了vm.$delete方法来删除数据种的某个属性,并且此时Vue.js可以侦测到数据发生了变化。

二、用法

vm.$delete(target,key)

(1)参数

  • {Object | Array} target
  • {string | number} key/index

注意:仅在2.2.0+版本中支持Array+index的用法。

(2)用法

1、删除对象的属性。

2、如果对象是响应式的,需要确保删除能触发更新视图。

3、这个方法主要用于避开Vue.js不能检测到属性被删除的限制。

4、在2.2.0+中,同样支持在数组上工作。

(3)注意

目标对象不能是Vue.js实例或Vue.js实例的根数据对象。

三、实现原理

(1)vm.$delete方法也是为了解决变化侦测的缺陷。在ES6之前,Javascript并没有办法侦测到一个属性在object中被删除,所以如果使用delete来删除一个数据,Vue.js根本不知道这个属性被删除了。

(2)使用vm.$delete能帮助我们在删除属性后自动向依赖发送消息,通知Watcher数据发生了变化。

(3)原理:删除属性后向依赖发消息

import {del} from '../observer/index'
Vue.prototype.$delete = del;

在Vue.js的原型上挂载$delete方法。

(4)del函数

export function del(target,key){
	const _ob_ = target._ob_;
	delete target[key];
	_ob_.dep.notify();
}

先从target中将属性key删除,然后向依赖发送消息。

(5)处理数组的情况

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();
}

因为使用了splice方法,数组拦截器会自动向依赖发送通知。

(6)与 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'
		)
		retun val;
	}
	delete target[key];
	_ob_.dep.notify();
}

1、如果target上有_isVue属性(target是Vue.js实例)或则ob.vmCount数量大于1(target是根数据),则直接返回,终止程序继续执行,并且如果是开发环境,会在控制台中发出警告。

(6)如果删除的这个key不是target自身的属性,就什么都不做,直接退出程序执行。

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'
		)
		retun val;
	}
	//如果key不是target自身的属性,则终止程序继续执行
	if(!hasOwn(target,key)){
		return;
	}
	delete target[key];
	_ob_.dep.notify();
}

(7)判断target是不是一个响应式数据,也就是说要判断target身上存不存在_ob_属性。只有响应式数据才需要发送通知,非响应式数据只需要执行删除操作即可。

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'
		)
		retun val;
	}
	//如果key不是target自身的属性,则终止程序继续执行
	if(!hasOwn(target,key)){
		return;
	}
	delete target[key];
	//如果ob不存在,则直接终止程序
	if(!_ob_){
		return;
	}
	_ob_.dep.notify();
}

如果数据不是响应式的,则使用return语句阻止执行发送通知语句。

你可能感兴趣的:(vue学习)