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

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

时间: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语音答题社群

    推荐阅读
  • 商务车都有啥(用车小知识商务车知多少)

    MPV车型主要是6座和7座,而SUV主要都是5座,座椅布局并没有MPV合理。SUV看起来大,但内部空间不如MPV。SUV底盘高度要比MPV车型高很多,所以通过性更好,可以在各种路况的道路上行驶,但是MPV车型就不行了,更适合在平整的道路上行驶。MPV的发动机是在车头,面包车的发动机在驾驶座下面,MPV的舒适性远高于面包车。

  • 最新漫画剪辑特效(漫画风格迁移神器)

    在A和B的对抗中,AI的水平逐渐提升,最后实现质的飞跃。另外在测试中发现app对照片的质量也是有要求的,模糊的大头照同样会使得人物的五官无法被精确捕捉。接下尝试上传动物的照片,同样从Pixabay获取素材。这次在选择小猫照片的时候特意挑选了一张表情奇特,且脸部有遮挡的照片,没想到AnimeGANv2还是出色地完成了任务。

  • 2023春节南阳月季园灯会交通指南 2020南阳月季展南阳园在哪

    2023春节南阳月季园灯会交通指南灯会时间:2023年1月14日至2023年2月6日景区地址:南阳市孔明北路独山收费站南500路西中国月季园公交信息:南阳15路公交到达士营下车后步行1.4KM即到,或者换乘到44路公交直接到“中国月季园”站下车2023年中国月季园第三届新春灯会,以“玉兔呈祥、灯耀南阳”为主题,引进灯会届的顶流——自贡花灯入驻!以弘扬民间传统文化,依托园区现有建筑景观,在地方特色民俗庙会的基础上融入众多流行元素。

  • 铁锅炒菜补铁吗(使用铁锅炒菜你能补铁吗)

    铁锅炒菜补铁吗虽然铁锅炒菜可以增加食物中的铁含量,但是这些铁都是无机铁,而人体吸收的都是有机化合物形态的铁,又被叫做血红素铁,在铁锅中能被人体吸收的血红素铁比例并不高,只能吸收3%左右。在贫困时期少量食用肉类时可以使用这种方法充铁元素,但是现在需要摄入铁元素可以直接从瘦肉或者肝脏中吸收,吸收铁元素的比例可以达到30%-50%之多。

  • 滚筒洗衣机可以用洗衣凝珠吗 滚筒洗衣机可以用洗衣凝珠吗?

    气味芬芳,质地软滑浓稠适中,性质温和不伤衣物,特有的低泡浓缩锁色配方,更易漂洗,凝珠遇水即溶无残留,还能有效快速去除顽固污渍让衣物洁净如新。

  • 湖南新田火棘果(湖北宜昌火棘果)

    ,下面我们就来聊聊关于湖南新田火棘果?接下来我们就一起去了解一下吧!

  • 微信怎么设置横屏模式(微信设置横屏模式的步骤)

    微信怎么设置横屏模式?打开手机,然后打开微信软件,如果手机内没有微信软件可以到应用市场搜索下载并安装,在微信主页面进入“我”界面,点击下方的“设置”选项;,我来为大家科普一下关于微信怎么设置横屏模式?以下内容希望对你有帮助!

  • 空气炸锅烤金针菇(空气炸锅烤金针菇的做法)

    下面更多详细答案一起来看看吧!空气炸锅烤金针菇空气炸锅烤金针菇的做法:金针菇切掉底部的根,洗干净,弄散成一条条,放在篮子里面沥一下水。剁好蒜蓉及切好葱白放入小碗中,加入适量盐,一勺酱油,一勺蚝油。空气炸锅铺好锡纸,然后放入金针菇和肉丸,再加入酱料。空气炸锅调200度烤12分钟,烤至7-8分钟的时候用筷子翻一下。出锅啦,加点辣椒酱,开吃。

  • 2016年这轮“猪周期”有望创下历史最高猪价

    养猪行情:继生猪市 场从2013年到2015年上半年经历了累计长达21个月的亏损之后,2016年猪价展现强劲的上涨势头,多家市场机构的数据显示,全国生猪出栏均价首次 破10元。

  • 鸿蒙os2.0系统怎么下载

    华为在HDC开发者大会上正式推出了鸿蒙OS2.0系统,该系统今天面向大屏、手表、车机发布开发者Beta版,12月发布手机版本,而明年华为智能手机将全面升级支持鸿蒙2.0。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持多种终端设备。