高频面试

MVVM分为Model、View、ViewModel三者

  • Model:代表数据模型,数据和业务逻辑都是在Model层定义
  • View:代表UI视图,负责对数据的展示
  • ViewModel: 负责监听Model中数据的改变并监控视图的更新,处理用户交互操作。

  Model和view并无直接关联,而是通过ViewModel来进行联系的,Model和ViewModel之间有着双向数据绑定的联系。因此当Model中数据改变时会触发View层刷新,View中由于用户交互操作而改变的数据也会在Model中同步。

  这种模式实现了Model和View的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作dom。

Vue2.x响应式数据/双向绑定原理

Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据。其中,View变化更新Data,可以通过事件监听的方式来实现,所以 Vue数据双向绑定的工作主要是如何根据Data变化更新View。

简述:

  • 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
  • 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
  • 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

深入理解:

  • 监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
  • 解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
  • 订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新——这是一个典型的观察者模式。
  •  订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。

你知道Vue3.x响应式数据原理吗?

Vue3.x改用Proxy替代Object.defineProperty。

因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化。

Proxy只会代理对象的第一层,Vue3是怎样处理这个问题的呢?

  • 判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。
  • 监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。

Proxy 与 Object.defineProperty 优劣对比,Proxy 的优势如下: 

  • Proxy 可以直接监听对象而非属性;
  • Proxy 可以直接监听数组的变化;
  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
  • Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
  • Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

对于组件通讯你了解多少,描述一下你是怎么完成组件的通讯

  • 父传子用props传递
  • 子传父用$emit传递
  • 非父子之间的传值,建立一个空实例进行传值,中央事件总线机制
  • 祖孙之间的传值可以利用provide inject模式
  • vuex可以处理上述的每一个情况

单页面首屏加载时间过长如何优化

  • 将共用的js库通过script标签在index.html进行外部引入,减少我们打包出来的js文件的大小,让浏览器并行下载资源文件,提高下载速度。
  • 在配置路由的时候进行路由的懒加载,在调用到改路由时,再加载次路由相对应的js文件。
  • 加一个首屏loading图或骨架屏,提高用户体验。
  • 尽可能使用css sprites和字体图标库
  • 图片的懒加载

 从输入网址到网页渲染完成经历了什么

  1. 输入网址按回车键或点击跳转
  2. 发送到DNS服务器进行DNS解析,获取到我们对应web服务器对应的ip地址
  3. 与web服务器简历TCP连接
  4. 浏览器想web服务器发送http请求
  5. Web服务器进行响应请求并返回指定的url数据
  6. 浏览器下载web服务器返回的数据及解析html源文件
  7. 根据文件生成DOM树和样式树合成我们的渲染树,解析js,最后渲染我们的页面然后显示出来。

关于修改了数据,视图不更新的理解和处理方式

vue中给data中的对象属性添加一个新的属性会发生什么?

经过打印发现数据是已经改变了,但是由于在vue实例创建时,新添加的属性并未声明,因此就没有被vue转换为响应式的属性,自然就不会触发视图的更新,

这是就需要用到Vue.set方法。

1 selectScore(shipInfo, item, subItem, thirdItem) {
2    thirdItem.isChecked = !thirdItem.isChecked;
3    Vue.set(thirdItem, 'selectFufenzhi', thirdItem.fufenzhi);
4     Vue.set(item, 'editValue', thirdItem.fufenzhi);
5 }
原文地址:https://www.cnblogs.com/guwufeiyang/p/13071851.html