Vue数据双向绑定原理(vue2向vue3的过渡)

简介: 众所周知,Vue的两大重要概念:数据驱动组件系统接下来我们浅析数据双向绑定的原理

一、vue2


1、认识defineProperty


vue2中的双向绑定是基于definePropertyget操作set操作,那么我们简单认识下defineProperty作用: 就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。 那么我们先来看下Object.getOwnPropertyDescriptor(),有定义方法就会有获取方法,对这就是与defineProperty相对的方法,它可以获取属性值。


var a ={
    b:1,
    c:2
}
console.log(Object.getOwnPropertyDescriptor(a,'b')); //查看获取b属性


网络异常,图片无法展示
|


这就是打印出来的结果,configurable的意思是可便利,enumerable的意思是可枚举,writable的意思是可写。


2、使用defineProperty实现简单的私有变量


知道了属性内部的属性值,我们可以使用defineProperty来实现一个私有变量。


var a ={
    b:1,
    c:2
}
Object.defineProperty(a,'b',{
    writable:false  //不可写
})
console.log(Object.getOwnPropertyDescriptor(a,'b')); //查看获取b属性


网络异常,图片无法展示
|


发现,改变不了a.b的值。


另外,还可以使用一个很快捷的方法实现私有变量


var a ={
    b:1,
    c:2
}
Object.freeze(a,'b'); //冻结,可理解为变为私有属性
// Object.seal(a,'b'); //configurable置为false 
console.log(Object.getOwnPropertyDescriptor(a,'b')); //查看获取b属性


网络异常,图片无法展示
|


同样,writable为false。如果使用seal()只能使configurable为false。


3、简单认识defineProperty的get、set的方法


我们先不要创建全局变量,跟get方法return值,你会发现值为undefined


网络异常,图片无法展示
|


于是我们改了改


var a ={
    b:1,
    c:2
}
 var _value=a.b; //b值赋值需要先赋给全局变量,不然使用不了
 Object.defineProperty(a,'b',{
    get:function(){
        console.log('get');
        return _value; // get方法必须ruturn值,值为全局变量。
    },
    set:function(newValue){
        console.log(newValue)
        _value=newValue; // 赋值
    }
 })


网络异常,图片无法展示
|


取到了。

4、使用defineProperty简单实现Vue双向绑定


test.js


// 使用defineProperty
function vue () {
    this.$data={
        a:1 // 数组的话不会更新
    };
    this.el=document.getElementById('app');
    this._html="";
    this.observe(this.$data);
    this.render();
};
vue.prototype.observe=function(obj){
    var value;
    var self=this;
    for(var key in obj){
        value =obj[key];
        if(typeof value === 'object'){
            this.observe(value)
        }else{
            Object.defineProperty(this.$data,key,{
                get:function(){
                    return value;
                },
                set:function(newvalue){
                    value=newvalue;
                    self.render();
                }
            })
        }
    }
}
vue.prototype.render=function(){
    this._html='I am '+ this.$data.a;
    this.el.innerHTML=this._html;
}
// ***************************************
//数组改变更新,装饰者模式
// var arraypro=Array.prototype;
// var arrayob=Object.create(arraypro);
// var arr = ["push","pop","shift"];
// // arr里的方法,既能保持原有的方法,又能触发更新。
// arr.forEach(function(method,index){
//     arrayob[method]=function(){
//         var ret=arraypro[method].apply(this,arguments);
//         console.log('更新');
//         return ret;
//     }
// })
// var arr=[];
// arr.__proto__=arrayob;
// arr.push(1);


test.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue双向绑定原理</title>
</head>
<body>
    <div id="app"></div>
</body>
<script src="test.js"></script>
<script>
    var vm = new vue();
    setTimeout(function(){
        console.log('changes');
        console.log(vm.$data);
        vm.$data.a=222;
    },2000)
</script>
</html>


这样我们就简单实现了数据双向绑定。


二、vue3


1、简单认识Proxy


就是一种机制,用来拦截外界对目标对象的访问,可以对这些访问进行过滤或者改写,所以Proxy更像是目标对象的代理器。


var ob= {
    a:1,
    b:2
}
// 新创建一个Proxy对象直接替换ob对象
ob=new Proxy(ob,{
    get:function(target,key,receive){   // target指的是原始对象,key指的是属性值,receive指的是这个Proxy对象
        console.log(target,key,receive) 
        return target[key]; //get方法 依然需要return
    },
    set:function(target,key,newvalue,receive){
        console.log(target,key,newvalue,receive) // newvalue指新创建的值
        target[key]=newvalue;
    }
});


这里需要注意的是:第一次使用proxy时,在new的时候把原对象替换掉。就会触发get方法


看到上方的代码,我们可以总结Proxy的几个优点:


  1. defineProperty只能监听某个属性,不能对全对象监听;
  2. 所以可以省去for in 提升效率;
  3. 可以监听数组,不用再去单独的对数组做异性操作。


2、使用Proxy简单实现数据双向绑定


test1.js


// 使用Proxy
function vue () {
    this.$data={
        a:1 
    };
    this.el=document.getElementById('app');
    this._html="";
    this.observe(this.$data);
    this.render();
};
vue.prototype.observe=function(obj){
    var self=this;
    this.$data=new Proxy(this.$data,{
        get:function(target,key){
            return target[key];
        },
        set:function(target,key,newvalue){
            target[key]=newvalue;
            self.render();
        }
    })
}
vue.prototype.render=function(){
    this._html='I am '+ this.$data.a;
    this.el.innerHTML=this._html;
}


test.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue双向绑定原理</title>
</head>
<body>
    <div id="app"></div>
</body>
<script src="test1.js"></script>
<script>
    var vm = new vue();
    setTimeout(function(){
        console.log('changes');
        console.log(vm.$data);
        vm.$data.a=222;
    },2000)
</script>
</html>


3、Proxy还可以做什么呢?


(1)、校验类型


function createValidator(target,validator){
    return new Proxy(target,{
        _validator:validator,
        set:function(target,key,value,proxy){
            if (target.hasOwnProperty(key)) {
                var validator1=this._validator[key];
                if(validator1(value)){
                    return Reflect.set(target,key,value,proxy)
                }
                else{
                    throw Error('type error')
                }
            }
        }
    })
}
var personvalidator={
    name(val){
        return typeof val==='string'
    },
    age(val){
        return typeof val==='number'&&val>18
    }
}
class Person {
    constructor(name,age) {
        this.name=name;
        this.age=age;
        return createValidator(this,personvalidator);
    }
}
var tss=new Person('maomin',22);


(2)、真正私有变量


var api = {
    _secret: 'xxxx',
    _otherSec: 'bbb',
    ver: 'v0.0.1'
};
api = new Proxy(api, {
    get: function (target, key) {
        // 以 _ 下划线开头的都认为是 私有的
        if (key.startsWith('_')) {
            console.log('私有变量不能被访问');
            return false;
        }
        return target[key];
    },
    set: function (target, key, value) {
        if (key.startsWith('_')) {
            console.log('私有变量不能被修改');
            return false;
        }
        target[key] = value;
    },
    has: function (target, key) {
        return key.startsWith('_') ? false : (key in target);
    }
});
api._secret; // 私有变量不能被访问
console.log(api.ver); // v0.0.1
api._otherSec = 3; // 私有变量不能被修改
console.log('_secret' in api); //false
console.log('ver' in api); //true



相关文章
|
7天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
11天前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
65 12
|
7天前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
7天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
|
2月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
148 1
|
28天前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
55 8
|
29天前
|
存储 设计模式 JavaScript
Vue 组件化开发:构建高质量应用的核心
本文深入探讨了 Vue.js 组件化开发的核心概念与最佳实践。
75 1
|
3月前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
111 58
|
2月前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
3月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
67 1
vue学习第一章

热门文章

最新文章