当前位置: 首页 > 后端技术 > Node.js

Vue3.0前端,不知道这些就晚了

时间:2023-04-03 10:09:48 Node.js

想看Vue3的源码,想知道Vue3的响应式原理,深度代理,如何避免多重触发,我想了解Vue3的Computed、Ref和Effect。要了解Vue3的DOM-Diff和模板编译,您必须了解这些基础知识:ProxyProxy可用于包装任何类型的对象,包括数组、函数甚至另一个代理。数据的处理,构造函数的处理,数据的校验,说白了就是在我们访问对象之前加一层拦截,可以过滤很多操作,而这些过滤器是你自己定义的。letproxy=newProxy(target,handler)target:需要被Proxy包裹的目标对象,可以是任何类型的对象,包括数组、函数,甚至是另一个proxy;handler:一个对象,其属性是在执行操作时定义代理行为的函数。举个栗子:letobj={name:'demo'};obj=newProxy(obj,{get(target,key,receiver){console.log('getterattributeobtained');if(key==='name'){target[key]='name:'+target[key];}returntarget[key];}})console.log(obj.name);//getter属性//name:demorecevier代表一个Proxy或者一个继承自Proxy的对象。这个例子非常简单。定义一个obj对象,然后通过Proxy进行包装。这时候obj就变成了一个Proxy实例,我们对obj的操作都会通过Proxy进行拦截。一些拦截操作也可以通过set来进行:letobj={name:'demo',age:10};obj=newProxy(obj,{set(target,key,value,receiver){if(key==='age'&&typeofvalue!=='number'){thrownewError('age字段必须是类型Number');}target[key]=value;returntrue;}});obj.age=12;console.日志(obj.age);//12obj.age='aaa';//错误:age字段必须是Number类型。set()方法应该返回一个true,表示在属性设置成功的handler中不只有get和set拦截器常用:handler.has()handler.ownKeys()handler.apply()handler.construct()handler.getPrototypeOf()handler.setPrototypeOf()handler.defineProperty()handler.deleteProperty()再举个栗子letobj={name:'hello',age:12};letp=newProxy(obj,{has(target,key){console.log('calledhas'+key);returnkeyintarget},ownKeys(target){console.log('calledownkeys');letarr=Reflect.ownKeys(target);returnarr;}});//调用自己的keysconsole.log(Object.keys(obj));//['name','age']//调用了nameconsole.log('name'inobj);//trueownKeys必须返回一个可枚举的对象,否则会违反Proxy约束并抛出类型错误同理,必须返回一个boolean属性的值。如果拦截的对象不可扩展或不可配置,则会违反约束并抛出类型错误。functionsum(...params){this.sum=params.reduce((prev,current)=>prev+current,0)returnthis.sum;}letp=newProxy(sum,{apply(target,thisArg,argumentList){console.log('calledapplyfn');returntarget(...argumentList)*10;},construct(target,argumentList,newTarget){returnnewtarget(...argumentList);}})//调用应用fnconsole.log(p(1,2,3,4));//100console.log(p(1,2,'3',4));//thrownewTypeError('参数必须是Number类型!')letres=newp(1,2,3,4);控制台日志(res.sum);//10apply用于拦截函数调用,target为目标函数,thisArg为调用时的上下文对象(即this指向),argumentList为调用时的参数数组。constructuser拦截new操作符,即new行为发生时函数会被拦截,所以被代理对象本身必须有construct内部方法。构造方法必须返回一个对象。ReflectReflect不是一个函数对象/构造器,所以不能用来new。Reflect的所有属性和方法都是静态的(就像Math一样)。Reflect最直接的表现就是保持JS简单,比如lets=Symbo('foo');letobj={name:'hello',age:12,[s]:1}console.log([s]);//getOwnPropertyNames获取字符串类型key;getOwnPropertySymbolsgetsSymboltypekeyletres=Object,getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))等价于lets=Symbol('foo');letobj={name:'hello',age:12,[s]:1}letres=Reflect.ownKeys(obj,'name');//['name','age',Symbol(foo)]Reflect采用了Object对象的一些方法,这些方法显然是语言内部的;修改一些Object方法的返回结果,比如Object.defineProperty()在属性不能定义的时候会抛出错误,而Reflect.defineProperty()会返回false;而Reflect将Object操作转化为函数式行为,将一些命令式操作转化为函数式行为,如nameinobj、deleteobj[name]等操作;只要Proxy对象中有方法,Reflect就和它一一对应,这样Proxy就更容易调用Reflect方法。我们再来看看Reflect.apply的用法。它通过指定的参数列表发起对目标函数的调用:letages=[11,33,12,54,18,96];让最年轻的=Reflect.apply(Math.min,Math,ages);控制台日志(最年轻的);//11可以理解为调用Math.min方法,this指向Math,参数为ages;相较于Math.min.apply(Math,ages),Reflect的最大优势在于可以避免别人已经写了一个同名的apply函数时写一长串的代码:Function.prototype.apply.call(context,...args)Reflect.set(target,key,value,receiver);Reflect.get(target,key,receiver);Reflect.has(target,key);Reflect.defineProperty(target,key,attributes);Reflect.deleteProperty(target,key);Reflect.getPrototypeOf(target);Reflect.setPrototypeOf(target,prototype);Reflect.isExtensible(target);//判断对象是否可扩展Reflect.getOwnPropertyDescriptor(target,key);//返回给定的属性描述符上面列出了Reflect的方法,下面是一些Properties的使用例子:letObj={name:'hello',age:12}console.log(Reflect.has(Obj,'name'));//trueconsole.log(Reflect.defineProperty(Obj,'sex',{value:'female'}));//trueconsole.log(Obj.sex);//femaleconsole.log(Reflect.deleteProperty(Obj,'年龄');//trueconsole.log(Obj.age);//undefined通过这个例子的演示,可以感受到反射机制主要是用来从一个类中获取额外的元信息,或者为类的一些方法添加注解,实时运行时获取相应的元信息.这不仅对一个对象有效,而且对Proxy和相应的陷阱也有效。WeakMapWeakMap`对象是键值对的集合,其中键是弱引用,键必须是对象,值可以是任意值。WeakMap是对每个key对象的弱引用,也就是说在没有其他引用的情况下,垃圾回收可以正确进行;但是因为是弱引用,所以WeakMap的key是不可枚举的。因此,如果想在不干扰垃圾回收机制的情况下向对象添加数据,可以选择WeakMap。让map=newWeakMap();让map2=newWeakMap();让obj1={};让obj2=function(){};让obj3=global;map.set(obj1,28);map.set(obj2,'绝对');map.set(obj3,undefined);console.log(map.get(obj1));//28console.log(map.get(obj2));//absoluteconsole.log(map.get(obj3));//undefinedconsole.log(map2.get(obj1));//undefinedconsole.log(map.has(obj1));//truemap.delete(obj1);console.log(map.has(obj1));//falseWeakMap在原型上只有四个方法:set、get、delete、has;这四种方法掌握起来非常简单,你现在已经了解WeakMap了吗?SetSet对象允许存储任何类型的唯一值。它是一个值的集合,同一个元素只会出现一次,即元素是唯一的。显示所有方法的示例letset=newSet();set.add(1);set.add(2);设置.添加(2);//重复值不添加set.add(3).add(4);//可以链接console.log(set);//Set{1,2}letobj={name:'hello',age:12};set.add(obj);set.add({name:'hello',age:12})//对象add和obj不是同一个引用对象,所以可以addconsole.log(set);//Set{1,2,{name:'hello',age:12},{name:'hello',age:12}}console.log(set.has(1));//如果Set对象中存在指定的值,则返回trueconsole.log(set.has(6));//false否则返回falseconsole.log(set.delete(1));//true指定元素删除成功则返回trueconsole.log(set.delete(6));//false否则返回falseconsole.log(set.has(1));//falseletsetIterator=set.entries();console.log(setIterator.next().value);//[2,2]console.log(setIterator.next().value);//[3,3]console.log(setIterator.next().value);//...console.log(setIterator.next().value);//[{name:'hello',age:12},{name:'h你好',年龄:12}]set.clear();//用于清除Set对象中的所有元素console.log(set)//Set{}值得注意的是entries方法,它返回一个新的迭代对象,类似于[value,value]形式的数组因为Set集合没有像Map那样有key,所以为了和Map形式保持一致,每一个entry的key和value都具有相同的value,所以是[value,value]形式。小结掌握这些基本概念,不仅对分析Vue3源码有帮助,而且对前端代码的未来趋势有一个了解。希望这篇文章能给大家提供一些帮助,喜欢的话请点个赞吧~