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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值