浅谈Vue双向数据绑定的原理

☞☞ 个人主页欢迎访问 ☜☜


大家好,我是苏日俪格,在很多次面试的时候, 面试官都会多多少少问到vue的双向数据绑定的原理是什么? 这个问题就很尴尬了, 我当初来现在的这家公司的时候初试和复试都遇到了这个问题, 不仅如此, 之前面试的几家公司也都问了这个让我值得深思又避免不了尴尬的问题, 在这两天完成了自己的任务后, 静了下心来回想一下这个问题.

在网上查找许多资料, 可能是IT界的大佬们讲的太专业太深奥了, 也可能是我真的真的是一个名副其实的理工科生, 对文字理解能力差吧, 可我还是没懂, 后来让我这个从来不爱读书的孩子在书中找到了这个黄金屋, 偶然发现了有关绑定数据属性的问题, 下面我把我的理解跟大家分享一下,本文纯属个人理解,有哪里不对的地方请在评论区指出,大家一起学习共同进步。

所谓双向数据绑定, 无非就是数据层和视图层中的数据同步, 在写入数据时视图层实时的跟着更新, 之前在网上看到大佬们是这么描述的:

实现mvvm的双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者

一共分四步, 每一步都有大堆解释和一大堆的代码, 然而我真的只是一个名副其实的理工科生, 看到了文中的发布者-订阅者模式, 于是乎我去网上各种百度, 个人理解就是getter函数里面执行的任务就是watcher订阅者, 而setter函数执行的任务就是发布者; 相信很多人看过了这个也是一知半解, 下面我来解释一波:

ECMAScript中有两种属性: 数据属性和访问器属性, 数据属性一般用于存储数据数值, 访问器属性对应的是set/get操作, 不能直接存储数据值, 每种属性下面又都含有四个特性.下面介绍一下:

数据属性

1.[[Configurable]]: 表示能否通过delete将属性删除,能否把属性修改为访问器属性, 默认为false。当把属性Configurable设置为false后,该属性不能通过delete删除,并且也无法再将该属性的Configurable设置回true
2.[[Enumerable]]: 表示属性可否被枚举(即是否可以通过for in循环返回),默认false
3.[[Writable]]: 表示属性是否可写(即是否可以修改属性的值),默认false
4.[[Value]]: 该属性的数据值, 默认是undefined

访问器属性

1.[[Configurable]]: 表示能否通过delete将属性删除,能否把属性修改为数据属性, 默认为false。当把属性Configurable设置为false后,该属性不能通过delete删除,并且也无法再将该属性的Configurable设置回true
2.[[Enumerable]]: 表示属性可否被枚举(即是否可以通过for in循环返回),默认false
3.[[Get]]: 读取属性时调用的函数, 默认为undefined
4.[[Set]]: 写入属性时调用的函数, 默认是undefined

在修改属性的特性或者定义访问器属性的时候, 需要借助ECMAScript 5中的一个方法: Object.defineProperty(), 这个方法接收三个参数: 属性所在对象, 属性的名字, 描述符对象; 为对象定义多个属性的话, 就用函数的复数写法:Object.defineProperties();

那么通过这个ES5的方法就可以直接很简单粗暴的说明双向绑定的原理:

<input type="text" id="inp" />
<div id="box"></div>
<script>
let obj = {};
let oInp = document.getElementById('inp');
let oBox = document.getElementById('box');
Object.defineProperty(obj, 'name', {
    configurable: true,
    enumerable: true,
    get: function() {
        console.log(111)
        return val;
    },
    set: function(newVal) {
        oInp.value = newVal;
        oBox.innerHTML = newVal;
    }
});
oInp.addEventListener('input', function(e) {
    obj.name = e.target.value;
});
obj.name = '苏日俪格';

那么实现数据双向绑定的核心就是利用为每一个属性都创建了订阅者的实例对象, 以便观察, getter函数里面返回一个value值,在setter函数中写入修改后的值并调用update方法更新视图的数据值, Configurable和Enumerable这两个特性描述符默认是true, 因此不用写

function defineReactive (obj, key, val) {
    var dep = new Dep();  //这是一个构造函数  其原型是为属性添加订阅者
    Object.defineProperty(obj, key, {
       get: function() {
            if(Dep.target) {
                dep.addSub(Dep.target);  //添加订阅者到Dep实例对象
            }
            return val;  // 返回监听到的value值
        },
        set: function (newVal) {
            if(newVal === val) return;
            val = newVal;  // 写入新的value值
            dep.notify();  // 作为发布者发出通知 然后dep会迭代调用各自的update方法来更新视图
        }
    });
}
function observe(obj, vm) {
     Object.keys(obj).forEach(function(key) {
           defineReactive(vm, key, obj[key]);
     });
}

根据此文章相关信息, 后来又写了一个简化版的Vue,希望可以帮助到大家,有兴趣的可以star/fork一下

如果想要仔细研究的可以参考一下他的博客或者http://www.cnblogs.com/canfoo/p/6891868.html

希望大家阅读完本文可以有所收获,因为能力有限,掌握的知识也是不够全面,欢迎大家提出来一起分享!谢谢O(∩_∩)O~

欢迎访问我的GitHub,喜欢的可以star,项目随意fork,支持转载但要下标注,同时恭候:个人博客

等一下( •́ .̫ •̀ ),我还有最后一句话:
我爱你,
他们说,
海最深邃,
干净而又透明 ,
我想 ,
是因为他们没有看到你的眼睛 ,
再见...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,098评论 0 6
  • 有时候光靠意识和想法是很难转变为行动的,《买买买时代的行为经济学》一书交给我们一个能让人行动起来的方法,叫做“替代...
    顺锅阅读 371评论 0 1
  • 趁着有空和朋友来了一趟雁荡山 风景很好,没有被过度开发,没有很多商铺。 可能是太热,没有多少游客 ...
    只有鱼丸没有面阅读 288评论 0 1
  • 有个很老的小故事,桌子上放一杯水。 悲观者会说,哎,只剩半杯了。 乐观者会说,哦,还好有半杯。 一杯水折射出来不同...
    九燊阅读 308评论 0 1