应用 Object.defineProperty() 来进行数据劫持有什么毛病?

在对一些属性进行操作时,应用这种办法无奈拦挡,比方通过下标形式批改数组数据或者给对象新增属性,这都不能触发组件的从新渲染,因为 Object.defineProperty 不能拦挡到这些操作。更准确的来说,对于数组而言,大部分操作都是拦挡不到的,只是 Vue 外部通过重写函数的形式解决了这个问题。

在 Vue3.0 中曾经不应用这种形式了,而是通过应用 Proxy 对对象进行代理,从而实现数据劫持。应用Proxy 的益处是它能够完满的监听到任何形式的数据扭转,惟一的毛病是兼容性的问题,因为 Proxy 是 ES6 的语法。

Vue 修饰符有哪些

事件修饰符

  • .stop 阻止事件持续流传
  • .prevent 阻止标签默认行为
  • .capture 应用事件捕捉模式,即元素本身触发的事件先在此处解决,而后才交由外部元素进行解决
  • .self 只当在 event.target 是以后元素本身时触发处理函数
  • .once 事件将只会触发一次
  • .passive 通知浏览器你不想阻止事件的默认行为

v-model 的修饰符

  • .lazy 通过这个修饰符,转变为在 change 事件再同步
  • .number 主动将用户的输出值转化为数值类型
  • .trim 主动过滤用户输出的首尾空格

键盘事件的修饰符

  • .enter
  • .tab
  • .delete (捕捉“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

零碎润饰键

  • .ctrl
  • .alt
  • .shift
  • .meta

鼠标按钮修饰符

  • .left
  • .right
  • .middle

delete和Vue.delete删除数组的区别

  • delete 只是被删除的元素变成了 empty/undefined 其余的元素的键值还是不变。
  • Vue.delete 间接删除了数组 扭转了数组的键值。

Vue complier 实现

  • 模板解析这种事,实质是将数据转化为一段 html ,最开始呈现在后端,通过各种解决吐给前端。随着各种 mv* 的衰亡,模板解析交由前端解决。
  • 总的来说,Vue complier 是将 template 转化成一个 render 字符串。
能够简略了解成以下步骤:
  • parse 过程,将 template 利用正则转化成AST 形象语法树。
  • optimize 过程,标记动态节点,后 diff 过程跳过动态节点,晋升性能。
  • generate 过程,生成 render 字符串

Vue.js的template编译

简而言之,就是先转化成AST树,再失去的render函数返回VNode(Vue的虚构DOM节点),具体步骤如下:

首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的形象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创立编译器的。另外compile还负责合并option。

而后,AST会通过generate(将AST语法树转化成render funtion字符串的过程)失去render函数,render的返回值是VNode,VNode是Vue的虚构DOM节点,外面有(标签名、子节点、文本等等)

对 SPA 单页面的了解,它的优缺点别离是什么?

SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载实现,SPA 不会因为用户的操作而进行页面的从新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,防止页面的从新加载。

长处:

  • 用户体验好、快,内容的扭转不须要从新加载整个页面,防止了不必要的跳转和反复渲染;
  • 基于下面一点,SPA 绝对对服务器压力小;
  • 前后端职责拆散,架构清晰,前端进行交互逻辑,后端负责数据处理;

毛病:

  • 首次加载耗时多:为实现单页 Web 利用性能及显示成果,须要在加载页面的时候将 JavaScript、CSS 对立加载,局部页面按需加载;
  • 后退后退路由治理:因为单页利用在一个页面中显示所有的内容,所以不能应用浏览器的后退后退性能,所有的页面切换须要本人建设堆栈治理;
  • SEO 难度较大:因为所有的内容都在一个页面中动静替换显示,所以在 SEO 上其有着人造的弱势。

参考 前端进阶面试题具体解答

mixin 和 mixins 区别

mixin 用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的。

Vue.mixin({  beforeCreate() {    // ...逻辑        // 这种形式会影响到每个组件的 beforeCreate 钩子函数  },});

尽管文档不倡议在利用中间接应用 mixin,然而如果不滥用的话也是很有帮忙的,比方能够全局混入封装好的 ajax 或者一些工具函数等等。

mixins 应该是最常应用的扩大组件的形式了。如果多个组件中有雷同的业务逻辑,就能够将这些逻辑剥离进去,通过 mixins 混入代码,比方上拉下拉加载数据这种逻辑等等。
另外须要留神的是 mixins 混入的钩子函数会先于组件内的钩子函数执行,并且在遇到同名选项的时候也会有选择性的进行合并。

说说Vue的生命周期吧

什么时候被调用?

  • beforeCreate :实例初始化之后,数据观测之前调用
  • created:实例创立万之后调用。实例实现:数据观测、属性和办法的运算、 watch/event 事件回调。无 $el .
  • beforeMount:在挂载之前调用,相干 render 函数首次被调用
  • mounted:了被新创建的vm.$el替换,并挂载到实例下来之后调用改钩子。
  • beforeUpdate:数据更新前调用,产生在虚构DOM从新渲染和打补丁,在这之后会调用改钩子。
  • updated:因为数据更改导致的虚构DOM从新渲染和打补丁,在这之后会调用改钩子。
  • beforeDestroy:实例销毁前调用,实例依然可用。
  • destroyed:实例销毁之后调用,调用后,Vue实例批示的所有货色都会解绑,所有事件监听器和所有子实例都会被移除

每个生命周期外部能够做什么?

  • created:实例曾经创立实现,因为他是最早触发的,所以能够进行一些数据、资源的申请。
  • mounted:实例曾经挂载实现,能够进行一些DOM操作。
  • beforeUpdate:能够在这个钩子中进一步的更改状态,不会触发重渲染。
  • updated:能够执行依赖于DOM的操作,然而要防止更改状态,可能会导致更新无线循环。
  • destroyed:能够执行一些优化操作,清空计时器,解除绑定事件。

ajax放在哪个生命周期?:个别放在 mounted 中,保障逻辑统一性,因为生命周期是同步执行的, ajax 是异步执行的。复数服务端渲染 ssr 同一放在 created 中,因为服务端渲染不反对 mounted 办法。 什么时候应用beforeDestroy?:以后页面应用 $on ,须要解绑事件。分明定时器。解除事件绑定, scroll mousemove

双向数据绑定的原理

Vue.js 是采纳数据劫持联合发布者-订阅者模式的形式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时公布音讯给订阅者,触发相应的监听回调。次要分为以下几个步骤:

  1. 须要observe的数据对象进行递归遍历,包含子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变动
  2. compile解析模板指令,将模板中的变量替换成数据,而后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,增加监听数据的订阅者,一旦数据有变动,收到告诉,更新视图
  3. Watcher订阅者是Observer和Compile之间通信的桥梁,次要做的事件是: ①在本身实例化时往属性订阅器(dep)外面增加本人 ②本身必须有一个update()办法 ③待属性变动dep.notice()告诉时,能调用本身的update()办法,并触发Compile中绑定的回调,则功成身退。
  4. MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听本人的model数据变动,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变动 -> 视图更新;视图交互变动(input) -> 数据model变更的双向绑定成果。

父子组件生命周期调用程序(简略)

渲染程序:先父后子,实现程序:先子后父

更新程序:父更新导致子更新,子更新实现后父

销毁程序:先父后子,实现程序:先子后父

nextTick在哪里应用?原理是?

  • nextTick 中的回调是在下次 DOM 更新循环完结之后执行提早回调,用于取得更新后的 DOM
  • 在批改数据之后立刻应用这个办法,获取更新后的 DOM
  • 次要思路就是采纳微工作优先的形式调用异步办法去执行 nextTick 包装的办法
nextTick 办法次要是应用了宏工作和微工作,定义了一个异步办法.屡次调用 nextTick 会将办法存入队列中,通过这个异步办法清空以后队列。所以这个 nextTick 办法就是异步办法

依据执行环境别离尝试采纳

  • 先采纳Promise
  • Promise不反对,再采纳MutationObserver
  • MutationObserver不反对,再采纳setImmediate
  • 如果以上都不行则采纳setTimeout
  • 最初执行flushCallbacks,把callbacks外面的数据顺次执行

[外链图片转存失败,源站可能有防盗链机制,倡议将图片保留下来间接上传(img-90qfr49E-1676945043471)(null)]

答复范例

  1. nextTick 中的回调是在下次 DOM 更新循环完结之后执行提早回调,用于取得更新后的 DOM
  2. Vue有个异步更新策略,意思是如果数据变动,Vue不会立即更新DOM,而是开启一个队列,把组件更新函数保留在队列中,在同一事件循环中产生的所有数据变更会异步的批量更新。这一策略导致咱们对数据的批改不会立即体现在DOM上,此时如果想要获取更新后的DOM状态,就须要应用nextTick
  3. 开发时,有两个场景咱们会用到nextTick
  4. created中想要获取DOM
  • 响应式数据变动后获取DOM更新后的状态,比方心愿获取列表更新后的高度
  • nextTick签名如下:function nextTick(callback?: () => void): Promise<void>

所以咱们只须要在传入的回调函数中拜访最新DOM状态即可,或者咱们能够await nextTick()办法返回的Promise之后做这件事

  1. Vue外部,nextTick之所以可能让咱们看到DOM更新后的后果,是因为咱们传入的callback会被增加到队列刷新函数(flushSchedulerQueue)的前面,这样等队列外部的更新函数都执行结束,所有DOM操作也就完结了,callback天然可能获取到最新的DOM值

根本应用

const vm = new Vue({    el: '#app',    data() {        return { a: 1 }    }}); // vm.$nextTick(() => {// [nextTick回调函数fn,外部更新flushSchedulerQueue]//     console.log(vm.$el.innerHTML)// })// 是将内容保护到一个数组里,最终依照程序程序。 第一次会开启一个异步工作vm.a = 'test'; // 批改了数据后并不会马上更新视图vm.$nextTick(() => {// [nextTick回调函数fn,外部更新flushSchedulerQueue]    console.log(vm.$el.innerHTML)})// nextTick中的办法会被放到 更新页面watcher的前面去

相干代码如下

// src/core/utils/nextTicklet callbacks = [];let pending = false;function flushCallbacks() {  pending = false; //把标记还原为false  // 顺次执行回调  for (let i = 0; i < callbacks.length; i++) {    callbacks[i]();  }}let timerFunc; //定义异步办法  采纳优雅降级if (typeof Promise !== "undefined") {  // 如果反对promise  const p = Promise.resolve();  timerFunc = () => {    p.then(flushCallbacks);  };} else if (typeof MutationObserver !== "undefined") {  // MutationObserver 次要是监听dom变动 也是一个异步办法  let counter = 1;  const observer = new MutationObserver(flushCallbacks);  const textNode = document.createTextNode(String(counter));  observer.observe(textNode, {    characterData: true,  });  timerFunc = () => {    counter = (counter + 1) % 2;    textNode.data = String(counter);  };} else if (typeof setImmediate !== "undefined") {  // 如果后面都不反对 判断setImmediate  timerFunc = () => {    setImmediate(flushCallbacks);  };} else {  // 最初降级采纳setTimeout  timerFunc = () => {    setTimeout(flushCallbacks, 0);  };}export function nextTick(cb) {  // 除了渲染watcher  还有用户本人手动调用的nextTick 一起被收集到数组  callbacks.push(cb);  if (!pending) {    // 如果屡次调用nextTick  只会执行一次异步 等异步队列清空之后再把标记变为false    pending = true;    timerFunc();  }}

数据更新的时候外部会调用nextTick

// src/core/observer/scheduler.jsexport function queueWatcher (watcher: Watcher) {  const id = watcher.id  if (has[id] == null) {    has[id] = true    if (!flushing) {      queue.push(watcher)    } else {      // if already flushing, splice the watcher based on its id      // if already past its id, it will be run next immediately.      let i = queue.length - 1      while (i > index && queue[i].id > watcher.id) {        i--      }      queue.splice(i + 1, 0, watcher)    }    // queue the flush    if (!waiting) {      waiting = true      if (process.env.NODE_ENV !== 'production' && !config.async) {        flushSchedulerQueue()        return      }      // 把更新办法放到数组中保护[nextTick回调函数,更新函数flushSchedulerQueue]      /**       * vm.a = 'test'; // 批改了数据后并不会马上更新视图        vm.$nextTick(() => {// [fn,更新]            console.log(vm.$el.innerHTML)        })       */      nextTick(flushSchedulerQueue)    }  }}

虚构DOM实现原理?

  • 虚构DOM实质上是JavaScript对象,是对实在DOM的形象
  • 状态变更时,记录新树和旧树的差别
  • 最初把差别更新到真正的dom中

你有对 Vue 我的项目进行哪些优化?

(1)代码层面的优化

  • v-if 和 v-show 辨别应用场景
  • computed 和 watch 辨别应用场景
  • v-for 遍历必须为 item 增加 key,且防止同时应用 v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片资源懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 优化有限列表性能
  • 服务端渲染 SSR or 预渲染

(2)Webpack 层面的优化

  • Webpack 对图片进行压缩
  • 缩小 ES6 转为 ES5 的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的 CSS
  • 优化 SourceMap
  • 构建后果输入剖析
  • Vue 我的项目的编译优化

(3)根底的 Web 技术的优化

  • 开启 gzip 压缩
  • 浏览器缓存
  • CDN 的应用
  • 应用 Chrome Performance 查找性能瓶颈

vue3.0 个性你有什么理解的吗?

Vue 3.0 正走在公布的路上,Vue 3.0 的指标是让 Vue 外围变得更小、更快、更弱小,因而 Vue 3.0 减少以下这些新个性:

(1)监测机制的扭转

3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言笼罩的反馈性跟踪。这打消了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限度:

  • 只能监测属性,不能监测对象
  • 检测属性的增加和删除;
  • 检测数组索引和长度的变更;
  • 反对 Map、Set、WeakMap 和 WeakSet。

新的 observer 还提供了以下个性:

  • 用于创立 observable 的公开 API。这为中小规模场景提供了简略轻量级的跨组件状态治理解决方案。
  • 默认采纳惰性察看。在 2.x 中,不论反应式数据有多大,都会在启动时被察看到。如果你的数据集很大,这可能会在利用启动时带来显著的开销。在 3.x 中,只察看用于渲染应用程序最后可见局部的数据。
  • 更准确的变更告诉。在 2.x 中,通过 Vue.set 强制增加新属性将导致依赖于该对象的 watcher 收到变更告诉。在 3.x 中,只有依赖于特定属性的 watcher 才会收到告诉。
  • 不可变的 observable:咱们能够创立值的“不可变”版本(即便是嵌套属性),除非零碎在外部临时将其“解禁”。这个机制可用于解冻 prop 传递或 Vuex 状态树以外的变动。
  • 更好的调试性能:咱们能够应用新的 renderTracked 和 renderTriggered 钩子准确地跟踪组件在什么时候以及为什么从新渲染。

(2)模板

模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会从新渲染,而 3.0 把作用域插槽改成了函数的形式,这样只会影响子组件的从新渲染,晋升了渲染的性能。

同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来不便习惯间接应用 api 来生成 vdom 。

(3)对象式的组件申明形式

vue2.x 中的组件是通过申明的形式传入一系列 option,和 TypeScript 的联合须要通过一些装璜器的形式来做,尽管能实现性能,然而比拟麻烦。3.0 批改了组件的申明形式,改成了类式的写法,这样使得和 TypeScript 的联合变得很容易。

此外,vue 的源码也改用了 TypeScript 来写。其实当代码的性能简单之后,必须有一个动态类型零碎来做一些辅助治理。当初 vue3.0 也全面改用 TypeScript 来重写了,更是使得对外裸露的 api 更容易联合 TypeScript。动态类型零碎对于简单代码的保护的确很有必要。

(4)其它方面的更改

vue3.0 的扭转是全面的,下面只波及到次要的 3 个方面,还有一些其余的更改:

  • 反对自定义渲染器,从而使得 weex 能够通过自定义渲染器的形式来扩大,而不是间接 fork 源码来改的形式。
  • 反对 Fragment(多个根节点)和 Protal(在 dom 其余局部渲染组建内容)组件,针对一些非凡的场景做了解决。
  • 基于 treeshaking 优化,提供了更多的内置性能。

说说你对 proxy 的了解,Proxy 相比于 defineProperty 的劣势

Object.defineProperty() 的问题次要有三个:

  • 不能监听数组的变动 :无奈监控到数组下标的变动,导致通过数组下标增加元素,不能实时响应
  • 必须遍历对象的每个属性 :只能劫持对象的属性,从而须要对每个对象,每个属性进行遍历,如果属性值是对象,还须要深度遍历。Proxy 能够劫持整个对象,并返回一个新的对象
  • 必须深层遍历嵌套的对象

Proxy的劣势如下:

  • 针对对象: 针对整个对象,而不是对象的某个属性 ,所以也就不须要对 keys 进行遍历
  • 反对数组:Proxy 不须要对数组的办法进行重载,省去了泛滥 hack,缩小代码量等于缩小了保护老本,而且规范的就是最好的
  • Proxy的第二个参数能够有 13 种拦挡方:不限于applyownKeysdeletePropertyhas等等是Object.defineProperty不具备的
  • Proxy返回的是一个新对象,咱们能够只操作新的对象达到目标,而Object.defineProperty只能遍历对象属性间接批改
  • Proxy作为新规范将受到浏览器厂商重点继续的性能优化,也就是传说中的新规范的性能红利

proxy具体应用点击查看(opens new window)

Object.defineProperty的劣势如下:

兼容性好,反对 IE9,而 Proxy 的存在浏览器兼容性问题,而且无奈用 polyfill 磨平

defineProperty的属性值有哪些

Object.defineProperty(obj, prop, descriptor)// obj 要定义属性的对象// prop 要定义或批改的属性的名称// descriptor 要定义或批改的属性描述符Object.defineProperty(obj,"name",{  value:"poetry", // 初始值  writable:true, // 该属性是否可写入  enumerable:true, // 该属性是否可被遍历失去(for...in, Object.keys等)  configurable:true, // 定该属性是否可被删除,且除writable外的其余描述符是否可被批改  get: function() {},  set: function(newVal) {}})

相干代码如下

import { mutableHandlers } from "./baseHandlers"; // 代理相干逻辑import { isObject } from "./util"; // 工具办法export function reactive(target) {  // 依据不同参数创立不同响应式对象  return createReactiveObject(target, mutableHandlers);}function createReactiveObject(target, baseHandler) {  if (!isObject(target)) {    return target;  }  const observed = new Proxy(target, baseHandler);  return observed;}const get = createGetter();const set = createSetter();function createGetter() {  return function get(target, key, receiver) {    // 对获取的值进行喷射    const res = Reflect.get(target, key, receiver);    console.log("属性获取", key);    if (isObject(res)) {      // 如果获取的值是对象类型,则返回以后对象的代理对象      return reactive(res);    }    return res;  };}function createSetter() {  return function set(target, key, value, receiver) {    const oldValue = target[key];    const hadKey = hasOwn(target, key);    const result = Reflect.set(target, key, value, receiver);    if (!hadKey) {      console.log("属性新增", key, value);    } else if (hasChanged(value, oldValue)) {      console.log("属性值被批改", key, value);    }    return result;  };}export const mutableHandlers = {  get, // 当获取属性时调用此办法  set, // 当批改属性时调用此办法};

Proxy只会代理对象的第一层,那么Vue3又是怎么解决这个问题的呢?

判断以后Reflect.get的返回值是否为Object,如果是则再通过reactive办法做代理, 这样就实现了深度观测。

监测数组的时候可能触发屡次get/set,那么如何避免触发屡次呢?

咱们能够判断key是否为以后被代理对象target本身属性,也能够判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger

为什么在 Vue3.0 采纳了 Proxy,摈弃了 Object.defineProperty?

Object.defineProperty 自身有肯定的监控到数组下标变动的能力,然而在 Vue 中,从性能/体验的性价比思考,尤大大就弃用了这个个性。为了解决这个问题,通过 vue 外部解决后能够应用以下几种办法来监听数组
push();pop();shift();unshift();splice();sort();reverse();

因为只针对了以上 7 种办法进行了 hack 解决,所以其余数组的属性也是检测不到的,还是具备肯定的局限性。

Object.defineProperty 只能劫持对象的属性,因而咱们须要对每个对象的每个属性进行遍历。Vue 2.x 里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么须要深度遍历,显然如果能劫持一个残缺的对象是才是更好的抉择。

Proxy 能够劫持整个对象,并返回一个新的对象。Proxy 不仅能够代理对象,还能够代理数组。还能够代理动静减少的属性。

什么是 mixin ?

  • Mixin 使咱们可能为 Vue 组件编写可插拔和可重用的性能。
  • 如果心愿在多个组件之间重用一组组件选项,例如生命周期 hook、 办法等,则能够将其编写为 mixin,并在组件中简略的援用它。
  • 而后将 mixin 的内容合并到组件中。如果你要在 mixin 中定义生命周期 hook,那么它在执行时将优化于组件自已的 hook。

Vue中封装的数组办法有哪些,其如何实现页面更新

在Vue中,对响应式解决利用的是Object.defineProperty对数据进行拦挡,而这个办法并不能监听到数组外部变动,数组长度变动,数组的截取变动等,所以须要对这些操作进行hack,让Vue能监听到其中的变动。 那Vue是如何实现让这些数组办法实现元素的实时更新的呢,上面是Vue中对这些办法的封装:

// 缓存数组原型const arrayProto = Array.prototype;// 实现 arrayMethods.__proto__ === Array.prototypeexport const arrayMethods = Object.create(arrayProto);// 须要进行性能拓展的办法const methodsToPatch = [  "push",  "pop",  "shift",  "unshift",  "splice",  "sort",  "reverse"];/** * Intercept mutating methods and emit events */methodsToPatch.forEach(function(method) {  // 缓存原生数组办法  const original = arrayProto[method];  def(arrayMethods, method, function mutator(...args) {    // 执行并缓存原生数组性能    const result = original.apply(this, args);    // 响应式解决    const ob = this.__ob__;    let inserted;    switch (method) {    // push、unshift会新增索引,所以要手动observer      case "push":      case "unshift":        inserted = args;        break;      // splice办法,如果传入了第三个参数,也会有索引退出,也要手动observer。      case "splice":        inserted = args.slice(2);        break;    }    //     if (inserted) ob.observeArray(inserted);// 获取插入的值,并设置响应式监听    // notify change    ob.dep.notify();// 告诉依赖更新    // 返回原生数组办法的执行后果    return result;  });});

简略来说就是,重写了数组中的那些原生办法,首先获取到这个数组的__ob__,也就是它的Observer对象,如果有新的值,就调用observeArray持续对新的值察看变动(也就是通过target__proto__ == arrayMethods来扭转了数组实例的型),而后手动调用notify,告诉渲染watcher,执行update。

MVVM的优缺点?

长处:

  • 拆散视图(View)和模型(Model),升高代码耦合,提⾼视图或者逻辑的重⽤性: ⽐如视图(View)能够独⽴于Model变动和批改,⼀个ViewModel能够绑定不同的"View"上,当View变动的时候Model不能够不变,当Model变动的时候View也能够不变。你能够把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多view重⽤这段视图逻辑
  • 提⾼可测试性: ViewModel的存在能够帮忙开发者更好地编写测试代码
  • ⾃动更新dom: 利⽤双向绑定,数据更新后视图⾃动更新,让开发者从繁琐的⼿动dom中解放

毛病:

  • Bug很难被调试: 因为使⽤双向绑定的模式,当你看到界⾯异样了,有可能是你View的代码有Bug,也可能是Model的代码有问题。数据绑定使得⼀个地位的Bug被疾速传递到别的地位,要定位原始出问题的地⽅就变得不那么容易了。另外,数据绑定的申明是指令式地写在View的模版当中的,这些内容是没方法去打断点debug的
  • ⼀个⼤的模块中model也会很⼤,尽管使⽤⽅便了也很容易保障了数据的⼀致性,过后⻓期持有,不开释内存就造成了破费更多的内存
  • 对于⼤型的图形应⽤程序,视图状态较多,ViewModel的构建和保护的老本都会⽐较⾼。

Vue 的生命周期办法有哪些 个别在哪一步发申请

beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在以后阶段 data、methods、computed 以及 watch 上的数据和办法都不能被拜访

created 实例曾经创立实现之后被调用。在这一步,实例已实现以下的配置:数据观测(data observer),属性和办法的运算, watch/event 事件回调。这里没有$el,如果非要想与 Dom 进行交互,能够通过 vm.$nextTick 来拜访 Dom

beforeMount 在挂载开始之前被调用:相干的 render 函数首次被调用。

mounted 在挂载实现后产生,在以后阶段,实在的 Dom 挂载结束,数据实现双向绑定,能够拜访到 Dom 节点

beforeUpdate 数据更新时调用,产生在虚构 DOM 从新渲染和打补丁(patch)之前。能够在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程

updated 产生在更新实现之后,以后阶段组件 Dom 已实现更新。要留神的是防止在此期间更改数据,因为这可能会导致有限循环的更新,该钩子在服务器端渲染期间不被调用。

beforeDestroy 实例销毁之前调用。在这一步,实例依然齐全可用。咱们能够在这时进行善后收尾工作,比方革除计时器。

destroyed Vue 实例销毁后调用。调用后,Vue 实例批示的所有货色都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。

activated keep-alive 专属,组件被激活时调用

deactivated keep-alive 专属,组件被销毁时调用

异步申请在哪一步发动?

能够在钩子函数 created、beforeMount、mounted 中进行异步申请,因为在这三个钩子函数中,data 曾经创立,能够将服务端端返回的数据进行赋值。

如果异步申请不须要依赖 Dom 举荐在 created 钩子函数中调用异步申请,因为在 created 钩子函数中调用异步申请有以下长处:

  • 能更快获取到服务端数据,缩小页面 loading 工夫;
  • ssr 不反对 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;