vue3.0和2.0数据绑定实现区别

vue3去年就已经发布了阿尔法版本,今年尤大表示只剩下些2.0的迁移工作,不过毕竟不想react和ng大树地下好乘凉,尤大单枪匹马的3.0究竟啥时候能到来谁也说不准,但是这并不耽误提前了解和学习,退一万步将哪怕胎死腹中,仍然可以嫖到思想。
github关注动态

简单聊下说烂了的2.0绑定方式,就是使用definedProperty中的get\set方法来完成数据劫持,之后在通过diff算法对比新老dom差异修改vdom,重新render完成渲染;
首先了解下definedProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法
Object.defineProperty(obj, prop, descriptor)

释义
obj要定义属性的对象。
prop要定义或修改的属性的名称或 Symbol 。
descriptor要定义或修改的属性描述符。

举个例子

	let obj = {};
	Object.defineProperty(obj, 'name', {
	  	value: 'dahuang',
	  	writable: false
	});
	console.log(obj.name);
	// 'dahuang'

主要看下descriptor中的属性

属性描述默认值
configurable描述符能否被改变false
enumerable能否被枚举false
value该属性对应的值。undefined。
writable能否被改写false
get当访问该属性时调用undefined
set当属性值被修改时调用。该方法接受一个被赋予的新值undefined

重点就是这个get和set,对何时触发再举个例子

	let obj = {a:1}
	Object.defineProperty(obj,'a',{
		get:function(){
		},
		set:function(){
		}
	})
	obj.a 			//触发get函数
	obj.a = 2		//触发set函数

了解了这些就可以创建一个简易版的响应式

	function vue(){}//不想起名字就还叫vue了
	vue.prototype.observe = function(obj){//完成数据绑定的方法
		var val;
		var that = this;
		for(let key in obj){//遍历所有属性,依次设置监听
			val = obj[key];
			if(typeof val ==='object'){
				this.observe(val)	//如果是对象的话进行递归
			}else{
				Object.defineProperty(this.$data,key,{
					get:function(){
						//vue中还会进行依赖收集,确定变量需要在哪部分修改,属于优化操作,这里先不考虑,有兴趣可以看源码dep对象
						//return this.$data[key]每次那到的都是上一次的值,所以外部保存变量
						return val;
					},
					set:function(newVal){
						val = newVal;
						that.render();
					}
				})
			}
		}
	}
	vue.prototype.render = function(){}//完成渲染的方法	

这里写的很糙,省去了很多东西,只是举个例子说下defineProperty,实际的vue中还做了很多别的,有兴趣可以看看源码,1040+行,或者想了解具体实现的推荐一篇博文
原理剖析

3.0由defineProperty改为了proxy;defineProperty是侵入原对象,改变了原有的一些东西,诸如枚举,读写之类的属性操作,上边列举属性表也可以看的出来,默认值都是false,换句话说就是默认的对象都是稳定的对象,而修改后就需要耗费额外的性能去做更多的处理;
proxy是一个代理,还是老规矩,先看属性

Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。

语法
const p = new Proxy(target, handler);

描述
target要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

handler对象方法

名称描述
handler.getPrototypeOf()Object.getPrototypeOf 方法的捕捉器。
handler.setPrototypeOf()Object.setPrototypeOf 方法的捕捉器。
handler.isExtensible()Object.isExtensible 方法的捕捉器。
handler.preventExtensions()Object.preventExtensions 方法的捕捉器。
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.defineProperty()Object.defineProperty 方法的捕捉器。
handler.has()in 操作符的捕捉器。
handler.get()属性读取操作的捕捉器。
handler.set()属性设置操作的捕捉器。
handler.deleteProperty()delete 操作符的捕捉器。
handler.ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
handler.apply()函数调用操作的捕捉器。
handler.construct()new 操作符的捕捉器。

重点还是看get\set,举个例子

	let a = {b:1,c:2}
	let proxya = new Proxy(a,{
		get:function(){},
		set:function(){}
	})

乍看上去好像没什么区别,不过这里不对a直接进行操作,而是返回一个代理对象proxya;从代码上来看,也比defineProperty省去了for循环遍历取值的操作,代码更加简洁
把上边observe中的defineProperty替换成proxy对比看下

	vue.prototype.observe = function(obj){
		let that = this;
		this.$data = new Proxy(this.$data,{
			get:function(tag,key){
				return tag[key]
			},
			set:function(tag,key,newVal){
				tag[key] = newVal;
				that.render();
			}
		})
	}

高下立判;

另外就是对vdom的对比进行了升级;
2.0的diff算法简单来讲会将所有的dom节点依次展开,并获取属性和子节点;一段div.wrap>p.txt1+p.txt2

	<div class='wrap'>
		<p class='txt1'>asd</p>
		<p class='txt2'>{{asd}}</p>
	</div>

展开大致就是

	Diff
	div
		att from div
		children from div
		innerHTML from div
			p
				att from p
				children from p
				innerHTML from p
			p
				att from p
				children from p 
				innerHTML from p

想表达的意思vdom会展开templent下所有节点,就是说如果txt1中并没有需要改变的数据,虚拟dom树在进行diff比对的时候仍然会展开并对比这个元素,无疑造成了性能的浪费;
3.0中又新增了一个block tree;对于目标模板,以vue指令进行切分,分成静态堆和动态堆,静态堆仅记录位置,而对比时只对比动态堆;
想了解block tree,可以参看vue3 bolck tree

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值