当前位置: 首页 > Web前端 > HTML

Vue双向绑定实现原理系列(一):Object.defineproperty

时间:2023-04-02 14:43:05 HTML

理解Object.defineProperty()github源码Object.defineProperty()方法直接在对象上定义一个新的属性,或者修改一个已有的属性,以及返回这个对象。VueJS使用ES5提供的Object.defineProperty()方法来监听数据的运行情况,从而自动触发数据同步。而且,由于同步是在不同的数据上触发的,所以更改可以精确地发送到绑定视图,而不是对所有数据执行检查。首先我们要知道ECMAScript中有两种属性:数据属性和访问器属性(ie8以下只能用在DOM对象上,不能用在普通对象上)数据属性:[[Configurable]]:表示是否可以修改Attributes。默认值为true[[Enumerable]]:表示属性是否可枚举,即属性是否可以通过for-in循环返回。默认值为true[[Writable]]:表示属性的值是否可以修改。默认值为true[[value]]:包含此属性的值。读取属性时,从这里开始读取。默认值为未定义的访问器属性:[[Configurable]]:指示属性是否可以修改。默认值为true[[Enumerable]]:表示属性是否可枚举,即属性是否可以通过for-in循环返回。默认值为true[[Get]]:读取属性时调用的函数,默认为undefined[[Set]]:设置属性时调用的函数,默认为undefined如果我们想修改默认属性,我们可以使用它:Object.defineProperty(obj,prop,descriptor);1、基本用法:vara={}Object.defineProperty(a,"b",{value:123});console.log(a.b);//1232。参数介绍:第一个参数obj:目标对象a第二个参数prop:要定义的属性或方法的名称“b”第二个参数descriptor:目标属性的特性2.1第三个参数的取值介绍(descriptor)value:属性的值writable:如果为false,则该属性的值不能被改写,只能是只读的。)enumerable:是否可以在for...in循环中遍历或者在Object.keys中列出。get:稍后介绍set:稍后介绍注意:不能同时设置访问器(get和set)和描述符中的wriable或value,否则会出错,也就是说,如果使用get和set,您不能在描述符中使用writable或value中的任何一个在基本用法中,仅设置value,不设置任何其他内容。可以简单理解(暂且),它会帮助我们默认设置可写、可配置、可枚举。都设置了值,值都是false。(仅限第一次设置),相当于如下代码:vara={};Object.defineProperty(a,'b',{value:123,writable:false,enumerable:false,configurable:false});控制台日志(a.b);//1232.1.1configurable引入主开关,第一次设置false后,第二次设置不起作用:也就是说可以使用Object.defineProperty()方法无限修改同一个属性,但是有将configurable更改为false时的限制vara={};Object.defineProperty(a,'b',{configurable:false});Object.defineProperty(a,'b',{configurable:true});//Error:UncaughtTypeError:Cannotredefineproperty:b(…)2.1.2可写介绍vara={};Object.defineProperty(a,'b',{value:123,writable:false//只读});控制台日志(a.b);//打印123a.b=124;//不会抛出错误(在严格模式下会抛出错误,即使之前已经有相同的值)console.log(a.b);//打印123,赋值不起作用。2.1.3enumerable介绍vara={}Object.defineProperty(a,"b",{value:3445,enumerable:true});console.log(Object.keys(a));//print["b"]//改为false:vara={}Object.defineProperty(a,"b",{value:3445,enumerable:false});console.log(Object.keys(a));//print[]2.1.4Set&get访问器属性不能直接定义!它们只能通过Object.defineProperty()定义:vara={}Object.defineProperty(a,"b",{set:function(newValue){console.log("Assignmentis:"+newValue)},get:function(){console.log("Value:")return2//注意这里,我硬编码为return2}});a.b=1;//赋值是:1console.log(a.b);//取值2总之,当b被赋值或取回时,分别触发set和get对应的函数3.Object.defineProperty例子://判断是否为对象函数isObj(obj){vartype=对象.prototype.toString.call(obj);returntype==='[objectObject]';}//执行函数:functionobjFun(obj){if(isObj(obj)){newObserver(obj);}}functionObserver(obj){this.data=obj;this.walk(obj);}//事件监听函数:Observer.prototype.walk=function(obj){for(varkinobj){def(obj,k,obj[k])}}functiondef(obj,k,val){Object.defineProperty(obj,k,{configurable:true,enumerable:true,get:function(){console.log('getvalue');returnval;},set:function(newVal){if(val===newVal){return;}val=newVal;console.log('设置设置值')}});}//测试:varobj={a:111,b:222};objFun(obj);console.log(obj.a)//获取值222obj.a=333;//设置settingvalueconsole.log(obj)4.Object.defineProperty实现数据与视图的联动:html:

Object.defineProperty实现数据与视图的联动:
js:(viewcontroller)varuserInfo={};Object.defineProperty(userInfo,'nickName',{get:function(){返回文档.getElementById('nickName').innerHTML;},set:function(nick){document.getElementById('nickName').innerHTML=尼克}});Object.defineProperty(userInfo,'introduce',{get:function(){returndocument.getElementById('introduce').innerHTML;},set:function(introduce){document.getElementById('introduce').innerHTML=introduce}});//console.log(userInfo)userInfo.nickName='我是昵称';userInfo.introduce='我是introduce'上面设置userInfo的nickName属性时,会调用set方法更新DOM节点HTML系列文章目录:Vue双向绑定实现原理系列(一):Object.definepropertyVue双向绑定实现原理系列(二):设计模式Vue双向绑定实现原理系列(三):ListenerObserver实现原理系列与订阅者WatcherVue的双向绑定(四):补充说明Parser编译