肥宅钓鱼网
当前位置: 首页 钓鱼百科

面试官问你的数据分析(说说你对双向绑定的理解)

时间:2023-07-04 作者: 小编 阅读量: 1 栏目名: 钓鱼百科

说说你对双向绑定的理解本文为面试官VUE系列总进度:3/33一、什么是双向绑定我们先从单向绑定切入单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向。

本文为面试官VUE系列总进度:3/33

一、什么是双向绑定

我们先从单向绑定切入

单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新

双向绑定就很容易联想到了,在单向绑定的基础,用户更新了ViewModel的数据也自动被更新了,这种情况就是双向绑定

举个栗子

当用户填写表单时,View的状态就被更新了,如果此时可以自动更新Model的状态,那就相当于我们把ModelView做了双向绑定

关系图如下

二、双向绑定的原理是什么

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑
  • 视图层(View):应用的展示效果,各类UI组件
  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来

而上面的这个分层的架构方案,可以用一个专业术语进行称呼:MVVM

这里的控制层的核心功能便是 “数据双向绑定” 。自然,我们只需弄懂它是什么,便可以进一步了解数据绑定的原理

理解ViewModel

它的主要职责就是:

  • 数据变化后更新视图
  • 视图变化后更新数据

当然,它还有两个主要部分组成

  • 监听器(Observer):对所有数据的属性进行监听
  • 解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

三、如何实现双向数据

我们还是以Vue为例,先来看看Vue中的双向绑定流程是什么的

  1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe

  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile

  3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数

  4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家dep来管理多个Watcher

  5. 将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

流程图如下:

实现

先来一个构造函数:执行初始化,对data执行响应化处理

class Vue {constructor(options) {this.$options = options;this.$data = options.data;// 对data选项做响应式处理observe(this.$data);// 代理data到vm上proxy(this);// 执行编译new Compile(options.el, this);}}

data选项执行响应化具体操作

function observe(obj) {if (typeof obj !== "object" || obj == null) {return;}new Observer(obj);}class Observer {constructor(value) {this.value = value;this.walk(value);}walk(obj) {Object.keys(obj).forEach((key) => {defineReactive(obj, key, obj[key]);});}}

编译Compile

对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

class Compile {constructor(el, vm) {this.$vm = vm;this.$el = document.querySelector(el);// 获取domif (this.$el) {this.compile(this.$el);}}compile(el) {const childNodes = el.childNodes;Array.from(childNodes).forEach((node) => { // 遍历子元素if (this.isElement(node)) {// 判断是否为节点console.log("编译元素"node.nodeName);} else if (this.isInterpolation(node)) {console.log("编译插值⽂本"node.textContent);// 判断是否为插值文本 {{}}}if (node.childNodes && node.childNodes.length > 0) {// 判断是否有子元素this.compile(node);// 对子元素进行递归遍历}});}isElement(node) {return node.nodeType == 1;}isInterpolation(node) {return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent);}}

依赖收集

视图中会用到data中某key,这称为依赖。同⼀个key可能出现多次,每次都需要收集出来用⼀个Watcher来维护它们,此过程称为依赖收集

多个Watcher需要⼀个Dep来管理,需要更新时由Dep统⼀通知

实现思路

  1. defineReactive时为每⼀个key创建⼀个Dep实例
  2. 初始化视图时读取某个key,例如name1,创建⼀个watcher1
  3. 由于触发name1getter方法,便将watcher1添加到name1对应的Dep中
  4. name1更新,setter触发时,便可通过对应Dep通知其管理所有Watcher更新

// 负责更新视图class Watcher {constructor(vm, key, updater) {this.vm = vmthis.key = keythis.updaterFn = updater// 创建实例时,把当前实例指定到Dep.target静态属性上Dep.target = this// 读一下key,触发getvm[key]// 置空Dep.target = null}// 未来执行dom更新函数,由dep调用的update() {this.updaterFn.call(this.vm, this.vm[this.key])}}

声明Dep

class Dep {constructor() {this.deps = [];// 依赖管理}addDep(dep) {this.deps.push(dep);}notify() {this.deps.forEach((dep) => dep.update());}}

创建watcher时触发getter

class Watcher {constructor(vm, key, updateFn) {Dep.target = this;this.vm[this.key];Dep.target = null;}}

依赖收集,创建Dep实例

function defineReactive(obj, key, val) {this.observe(val);const dep = new Dep();Object.defineProperty(obj, key, {get() {Dep.target && dep.addDep(Dep.target);// Dep.target也就是Watcher实例return val;},set(newVal) {if (newVal === val) return;dep.notify(); // 通知dep执行更新方法},});}

参考文献

  • https://www.liaoxuefeng.com/wiki/1022910821149312/1109527162256416
  • https://juejin.cn/post/6844903942254510087#heading-9
  • https://vue3js.cn

    @JS语音答题社群

    推荐阅读
  • 其远而无所至极邪的其的用法(其远而无所至极邪的其的用法是什么)

    全篇一再阐述无所依凭的主张,追求精神世界的绝对自由。在庄子的眼里,客观现实中的一事一物,包括人类本身都是对立而又相互依存的,这就没有绝对的自由,要想无所依凭就得无己。因而他希望一切顺乎自然,超脱于现实,否定人在社会生活中的一切作用,把人类的生活与万物的生存混为一体;提倡不滞于物,追求无条件的精神自由。

  • 梭鱼草是水生植物吗(梭鱼草是不是水生植物)

    梭鱼草是水生植物,它是一种多年生挺水或湿生草本植物。梭鱼草的花期较长,是一种观赏价值较高的水生植物。梭鱼草喜欢光照,生长期需要满足充足的光照,温度保持在18-35℃之间。梭鱼草喜湿、喜肥,养殖的时候水肥一定充足。梭鱼草适合在静水当中生长,一般20厘米以下的浅水适合其生长,盆栽时需灌满水。梭鱼草不耐寒,冬季温度低的时候需要进行防寒,可以将梭鱼草的盆栽灌水并放进室内越冬,保持温度在5℃以上,梭鱼草即可安全过冬。

  • 海底椰的常见吃法(海底椰的家常吃法)

    海底椰的常见吃法海底椰炖雪梨:海底椰炖雪梨是海底椰的常见吃法之一,在炖制时需要准备雪梨一个,海底椰十片,红枣适量,川贝五克,皂角米适量,冰糖和清水适量。把准备好的皂角料提前碾碎,红枣也剪成小块,川贝用清水泡,海底椰也用清水泡软。(4:烧开以后调小火力,慢慢的炖制一个小时左右,海底椰炖雪梨就能做好,取出降温即可食用,这种海底椰炖雪梨可以清热解毒,能有效预防人类的感冒。

  • 雪莲果怎么保存不发芽(雪莲果保存不发芽的方法)

    跟着小编一起来看一看吧!冰箱冷藏保存可使雪莲果不发芽,适宜雪莲果生长的温度约为18~24摄氏度,而冰箱冷藏层的温度在0~8摄氏度,雪莲果放在冰箱冷藏保存,可以抑制雪莲果的发育,能够有效防止雪莲果出现发芽的情况。

  • qq网名女生带符号(qq网名女生带符号霸气)

    1、smple﹑╮.靜待2、勾勾メ小手指☆3、╓習慣╮4、穎子╮五月5、10年╮后的伤°6、你の怀抱丶只许我停留7、﹎﹎﹎Venus╮偏爱、8、薰衣草的美╮依稀眷9、岸与海的距离10、海棠未雨11、笔小新的放纵与坚持12、伱⑩涐旳.╮緈諨13、说不出的悲伤╮谁懂14、斯守一苼15、~古仔~啦啦啦16、﹌有点、苦涩17、∮°染不尽的余温-18、≦玲静≧19、佑手边╮幸福20、街边、丢幸福21、dear丶妖孽╮ゞ22、姑娘我不懂温柔╮

  • 秦皇岛城镇职工医保意外伤害住院就医流程

    不属于基本医疗保险意外伤害报销范围的,告知参保患者医疗费用不能纳入基本医疗保险支付范围。《秦皇岛市城镇职工基本医疗保险意外伤害承诺书》留存在患者住院病历中。

  • 江西幼儿园命案嫌犯身份(江西安福县幼儿园命案嫌犯落网)

    江西一男子伪装、持械,闯入幼儿园内行凶,造成3死6伤。8月3号这起震惊全国的江西安福县幼儿园命案有了最新进展。据警方通报:当晚22点50分左右,警方在万安县韶口乡将犯罪嫌疑人刘小辉成功抓捕归案。从网上流传的现场视频来看,嫌疑人在一段高速公路旁被捕,疑似受伤。从地图上看,韶口乡距离案发地约有100公里。另有网传的一份截图显示,2017年4月,刘小辉因故意伤害案被“纳入部级重点人员”,但这一信息并没有得到警方证实。

  • 重点城建基础设施复工(聚焦基础设施疑难急险)

    2022年8月21日,新型建筑工业化与绿色智慧建造研讨会暨坝道工程医院山东城建分院成立大会在山东城市建设职业学院成功举办。“坝道工程医院山东城建分院的成立,是教育链、人才链与产业链、创新链的有机衔接,今后,山东大学将积极支持山东城市建设职业学院坝道工程医院开展工作,共同推动山东职业教育的科技产业发展。”山东城市建设职业学院党委书记花景新主持了第二阶段的会议。

  • 银行卡里只有一百块钱为什么取不出来? 银行卡里只有一百块钱取不出来原因

    3、卡片状态不正常或失磁:需要确认下近期是否有逾期还款等情况,如是失磁可找其他机器试下。

  • 红宝公鸡的养殖方法(养红公鸡需要注意什么)

    红宝公鸡在养殖前养殖地一定要消毒处理才行,可用石灰水或者是高锰酸钾溶液消毒。先在棚内养,注意防止鼠蛇侵害。初期个体小,适量也小,可养的密些。后期长大后要分开,不可太密。平时要多注意天气情况,不可淋雨。一般14天前的,每天喂养三次,喂全价饲料。14天后的每天两次,要逐渐增加原粮饲料。