0
点赞
收藏
分享

微信扫一扫

ES5 数据劫持—Object.defineProperty(干货)

本篇文章,着重来说下ES5中的Object.defineProperty两个非常重要的方法:getter方法和setter方法,别的属性百度一下一大堆,且讲的很详细。

在vue2.0中数据的双向绑定底层原理就是用的Object.defineProperty,当然马上要出的vue3.0用的是ES6的proxy(代理)实现双向绑定,具体区别以及proxy的用法我会在下一篇文章详细介绍。。。

Object.defineProperty( )

此方法可以在一个对象上定义新的属性,或者改变原有属性,返回这个对象。

语法:

Object.defineProperty(obj,key,disciptor)

     obj : 需要定义属性的对象;

     key:需要被定义或被修改的属性名;

     discriptor:将要被定义或修改的属性描述。

第三个参数discriptor它是一个对象,这个对象里有两个方法分别是get和set方法,还是用代码说下:

var obj = {
name:"lxc"
};

//相当于

var defaultObj = {};
Object.defineProperty(obj,"name",{
get(){
return defaultObj.name;
},
set(newValue){
defaultObj.name = newValue;
}
})

上边代码,obj设置了name属性,

相当于:

调用object.defineProperty中的set方法,唯一的参数newValue是:给obj.name设置的属性值,上边的是   "lxc" ;这里为了方便理解,声明了一个空对象,作为中间数据(传递属性值),让设置的属性值赋值给空对象defaultObj的name属性,这样取值得时候直接返回defaultObj的name属性值即可;

obj.name的时候,调用的是object.defineProperty中的get方法,方法必须要有return返回值,返回的属性值正是之前定义的 "lxc"。。。

 

在vue2.0中数据的双向绑定我们来简单实现下:

首先说下思路,其实很简单的一个思路,视图层的改变驱动数据变化,数据改变影响视图层,但是怎么用代码实现呢;

先看下视图层的改变可以影响数据:

这个很好实现,假设输入框作为视图层,给输入框加上input事件,让input.value 等于对象的属性,即可改变数据;

数据改变影响视图层:

首先遍历对象,因为我们要知道对象的那一个属性值变化了,,把对象和属性值传给Object.defineProperty(),如果修改属性值,会调用set方法,把新修改的值赋值给对象属性即可,然后把属性值渲染后页面。。。(这里边有几个细节点我在代码中解释了,有看不懂的地方,欢迎大家骚扰。。。)

代码详细说下 :

<div id="app">
<input type="text" id="inp"> //input控制器
<h1 id="h"></h1> //h1标签作为数据显示层
</div>
<script>
var view = document.getElementById("h");
var inp = document.getElementById("inp");

//数据
var obj = {
name:"lxc"
};

// ++++++++++++++++++++++++++++++++++下边是:视图层改变影响数据层
inp.onchange = function(){
upDataView.call(this) //这里之所以要掉用call因为下边函数中的this指向window
}
function upDataViewFn(){
obj.name = this.value
}


//++++++++++++++++++++++++++++++++++++下边是:数据变化影响视图层

// upData函数用来渲染数据,如果obj.name改变,则视图也会改变
function upData(){
view.innerText = obj.name;//把属性值赋给视图层的h1标签
inp.value = obj.name; //把属性赋给input框,也就是说数据改变了,h1和input框的都会发生改变
}

// observer函数用来循环对象,把对象、对象的属性、对象的属性值,传给objectRective函数
function observer(myObj){
//判断是否是对象 ,否则直接返回myObj ,也是递归的出口
if( !myObj || typeof myObj != "object" ){
return myObj;
}
Object.keys(myObj).forEach(key=>{
objectRective(myObj,key,myObj[key])
})
}
observer(obj)

// defaultRective函数用来监听obj对象的变化
function defaultRective(myObj,key,val){
observer(key);//递归调用observer函数,因为对象的属性可能又是一个对象,所以我们再次循环key,出口正是上边的if判断,如果key不是对象直接直接返回自身
Object.defineProperty(myObj,key,{
get(){
return val;//val是对象的属性值,如果要取对象的属性值,直接返回val
},
set(newVal){//如果修改对象的属性值,判断下赋值是否一样,一样就直接返回,不同则把新值赋值给val,执行upData数据渲染
if(newVal == myObj)return
val = newVal;
upData();
}
})
}

 


举报

相关推荐

0 条评论