Object.defineProperty() 以及 vue 中双数据绑定的底层原理

Object是在javascript中一个被我们经常使用的类型,而且JS中的所有对象都是继承自Object对象的。虽说我们平时只是简单地使用了Object对象来存储数据,并没有使用到太多其他功能,但是Object对象其实包含了很多很有用的属性和方法,尤其是ES5增加的方法,今天我们先探讨一下Object.defineProperty()。

Object.defineProperty

给一个对象添加或者修改属性 返回的是一个对象

语法

Object.defineProperty(obj, prop, descriptor)

参数

obj要在其上定义属性的对象。

prop要定义或修改的属性的名称。

descriptor将被定义或修改的属性描述符。

属性描述符是一个对象,参数如下

value: 设置属性值

writeable: 设置当前属性是否允许被修改

configurable:设置当前属性是否可以删除

enumerable:设置当前属性是否可被枚举

getter---get() 当获取属性值的时候触发的函数

setter---set() 当设置属性的时候触发的函数

注意:当使用了get()方法或者set()方法的时候就不能使用value和writable中的任何一个属性否则会报错

Vue-model底层原理

利用了es5中的object.defineProperty()方法中的set()get()属性对数据进行劫持

我们先来写一个简单版的mvvm

结构层为

<body>
    <input type="text" id="txt">
    <p id="msg"></p>
</body>

行为层代码为

    var obj = {message:"mvvm-demo"}
    var oTxt = document.getElementById("txt");
    var oMsg = document.getElementById("msg");

    Object.defineProperty(obj,"message",{
        configurable:true,
        enumerable:true,
        set:function(newStr){
            oMsg.innerText = newStr;
        }
    })

    oTxt.addEventListener("input",function(){
        obj.message = oTxt.value;
    })

  实现效果图如下

接下来我们来模拟一下vue中MVVM底层原理

结构层代码

<body>
    <div id="app">
        <input type="text" v-model="message">
        <p>{{message}}</p>

        <input type="text" v-model="name">
        <p>{{name}}</p>
    </div>

</body>

行为层代码

function Vue(options){
    this.el = document.querySelector(options.el);
    this.data = options.data;
    //是数据层和view之间的一个映射关系这里面存放这个需要双数据绑定的元素和当前元素的一些特征
    this.viewModel = {};

    this.init(this.data);
    this.eventType(this.el);
}

Vue.prototype = {
    constructor:Vue,
    init:function(obj){
        var _this = this;
        Object.keys(obj).forEach(function(key){
            var value = obj[key];
            //将当前key值作用的元素一些特征保存在这个数组里面
            _this.viewModel[key] = {
                _directive:[]
            }
            console.log(_this.viewModel)
            Object.defineProperty(obj,key,{
                configurable:true,
                enumerable:true,
                get:function(){
                    return value;
                },
                set:function(newValue){
                    if(newValue!=value){
                        value = newValue;
                        //数据更新
                        _this.viewModel[key]._directive.forEach(function(item){
                            item.update();
                        })
                    }
                }
            })
        })
    },
    eventType:function(root){
        var childs = root.children;
        var _this = this;
        for(var i=0;i<childs.length;i++){
            if(childs[i].hasAttribute("v-model") && childs[i].tagName == "INPUT"){
                childs[i].addEventListener("input",(function(i){
                    var attr = childs[i].getAttribute("v-model");
                    _this.viewModel[attr]._directive.push(new watch(
                        childs[i].tagName,
                        "value",
                        childs[i],
                        _this,
                        attr
                    ))
                    return function(){
                        //vm.data.message =
                        _this.data[attr] = childs[i].value;
                    }

                })(i))
            }

            if(childs[i].innerText.replace(/\{\{|\}\}/g,"")){
                var dataAttr = childs[i].innerText.replace(/\{\{|\}\}/g,"");
                _this.viewModel[dataAttr]._directive.push(new watch(
                        childs[i].tagName,
                        "innerText",
                        childs[i],
                        _this,
                        dataAttr
                ))
            }
        }
    }
}

//更新数据的方法  标签的名称  当前元素  当前元素的属性   vue的实例  data属性
function watch(name,exp,el,vm,attr){
    this.name = name;
    this.exp = exp;
    this.el = el;
    this.vm = vm;
    this.attr = attr;
    this.update();
}
watch.prototype.update = function(){
    this.el[this.exp] = this.vm.data[this.attr];
}

var vm = new Vue({
    el:"#app",
    data:{
        message:"demo",
        name:"mvvm"
    }
})

  

效果实现图如下



原文地址:https://www.cnblogs.com/w-819/p/9747314.html

时间: 2024-10-07 17:13:42

Object.defineProperty() 以及 vue 中双数据绑定的底层原理的相关文章

Vue中 key keep-alive的实现原理

vue2.0提供了一个keep-alive组件用来缓存组件,避免多次加载相应的组件,减少性能消耗 keep-aliv是Vue.js的一个内置组件.它能够不活动的组件实例保存在内存中,而不是直接将其销毁,它是一个抽象组件,不会被渲染到真实DOM中,也不会出现在父组件链中. 它有两个生命周期: activated: keep-alive组件激活时调用 deactivated: keep-alive组件停用时调用 它提供了include与exclude两个属性,允许组件有条件地进行缓存. keep-a

SQL中 left join 的底层原理

介绍 left join的实现效果就是保留左表的全部信息,将右表往左表上拼接,如果拼不上则为NULL. 除了left join以外,还有inner join.outer join.right join等,文章不介绍其他连接的具体效果,主要讲解join的底层原理是如何实现的?具体效果是怎样呈现的? 只有懂得了底层原理,才能更好的写出性能优越的SQL脚本,提高SQL的执行速度. join主要有3种方式,具体为: Nested Loop -- 嵌套循环,细分为以下3种连接方式: Simple Nest

vue中的数据绑定

1:文本插值 使用双大括号{{}} 也支持单次插值,即首次赋值后再更改vue实例中的属性值不会引起DOM变化. 例如: 注意:在vue1.0中采用的是{{*msg}}进行单此绑定,在vue2.0中已经剔除了这种写法,采用了v-once这种写法. 2:绑定html属性值 注意:用v-bind:来进行属性值的绑定,可以简写. 3:绑定表达式 4:输出HTML(v-html) 输出的结果是: 5:双向数据绑定 双向数据绑定一般使用在表单元素上(input select textarea),使用v-mo

通俗易懂了解Vue中nextTick的内部实现原理

狮子捕获猎物靠的不是牙尖嘴利,王者都是耐得住寂寞的,等待时机,一击必杀!导师企鹅:2901583663加了带你上岸加了带你上岸千万不要借本来玩,除非你有足够娴熟的技术和很强的心理素质.如果这两项你都不具备,那么你就是再有钱,我也不建 议你玩,谁的钱都不是大风刮来的,每一分钱都来之不易,不要轻易让自己的钱如流水.如果你此刻十分困难,不要灰心,放平心态,先想想此刻对你来说,到底什么最为重要,是技术还是本金,是心态还是人 脉,把自己梳理清晰,然后设定好步骤,不要慌不要乱,天无绝人之路,勇敢站起来,你可

vue中实现双向数据绑定原理,使用了Object.defineproperty()方法,方法简单

在vue中双向数据绑定原理,我们一般都是用v-model来实现的 ,但一般在面试话会问到其实现的原理, 方法比较简单,就是利用了es5中的一个方法.Object.defineproperty(),它有三个参数, Object.defineproperty(obj,'val',attrObject), 参数1: obj是属性所在的对象,参数2: 'val',属性名,它是一个string类型,参数3: {}属性所描述的对象 详情可以看Object.defineproperty的文档 下面直接上dem

MVVM双向绑定实现之Object.defineProperty

随着web应用的发展,直接操作dom的应用已渐行渐远,取而代之的是时下越来越流行的MVVM框架,dom操作几乎绝迹,这里面自然是框架底层封装的结果.MVVM框架的双向数据绑定使开发效率大大提高:然后在实现这些双向数据绑定时,使用ES7原生的Object.observe方法则是完美解决方案,但是遗憾的是该方法目前还是ES7的草案阶段,各浏览器还不支持,目前chrome 36+支持该方法. 既然Object.observe不被支持,但是其替代方案是ECMAScript 262v5带来的新东西Obje

深入理解 Object.defineProperty

Object.defineProperty() 和 Proxy 对象,都可以用来对数据的劫持操作.何为数据劫持呢?就是在我们访问或者修改某个对象的某个属性的时候,通过一段代码进行拦截行为,然后进行额外的操作,然后返回结果.那么vue中双向数据绑定就是一个典型的应用. Vue2.x 是使用 Object.defindProperty(),来进行对对象的监听的.Vue3.x 版本之后就改用Proxy进行实现的.下面我们先来理解下Object.defineProperty作用. 一: 理解Object

vue中的双向绑定

概述 今天对双向绑定感兴趣了,于是去查了下相关文章,发现有用脏检查的(angular.js),有用发布者-订阅者模式的(JQuery),也有用Object.defineProperty的(vue),其中用Object.defineProperty的(vue)特别简单,今天顺便记录下供以后开发时参考,相信对其他人也有用. 我参考了这篇文章:Vue.js双向绑定的实现原理. 类似双向绑定的效果 其实用事件代理就可以实现类似双向绑定的效果,原理是当检测到数据改动时会触发一个keyup事件或者表单的ch

Vue中的响应式原理

Vue最独特的特性之一,是其非侵入性的响应式系统. 响应式原理:数据变,页面变 Vue如何追踪变化 当把一个普通的JS对象传入Vue实例作为data选项时,Vue将遍历此对象的所有属性,并使用Object.defineProperty把这些属性全部转为getter/setter.Object.defineProperty是ES5中一个无法shim的特性,这也是Vue不支持IE8以及更低版本浏览器的原因. Object.defineProperty(obj, prop, descriptor)//