面试题草稿

208 阅读13分钟

Vue

1、vue和react的区别

1、 相同:

  • 响应式(Reactive)。两个框架都是一种类似 VM 的架构,将状态从视图层分离出来,开发者只需要关注业务逻辑,不需要直接操作 DOM 。当应用发生改变时,我们只需要更新状态即可,框架会自动帮我们重新渲染页面。

  • 组件化(Composable)。一个页面,可以拆分成一棵嵌套的组件树,我们只需要开发一个个组件即可,同一个组件可以在多个地方使用,这样就提升了代码的复用性和可维护性。

  • Virtual DOM。框架在操作真实 DOM 之前,会先在内存中生成虚拟 DOM,最后再批量操作真实 DOM,以提高性能。

2、不同:

  • 响应式原理不同;
  • Vue 推荐使用模版的方式定义组件,React 推荐使用 JSX;
  • React 推荐使用不可变的数据;

3、相关知识导航: 响应原理不同,请看第6#。

2、数据结构

3、promise

3、MVC

M:数据模型、V:视图、c:业务逻辑控制

介绍:早期是针对后端来说的,在页面中进行操作,比如说点击按钮,它会发起请求要资源,它会去请求后端的路由,通过控制器(业务逻辑操作)去获取数据,获取完再经过控制器回传给页面。

介绍2:MVC是应用最广泛的软件架构之一,一般MVC分为:Model(模型),View(视图),Controller(控制器)。 这主要是基于分层的目的,让彼此的职责分开.View一般用过Controller来和Model进行联系。ControllerModelView的协调者,ViewModel不直接联系。基本都是单向联系。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。MVC是单向通信。也就是ViewModel,必须通过Controller来承上启下。

缺点:

  • 大量的逻辑会耦合在c那一层,导致维护困难。
  • 前后端无法独立开发,太依赖后台

(因为MVC有那些问题,所以现在主流的解决方法就是用MVVM模式)

4、MVVM相当于前端有了自己的视图控制器

M:数据模型、V:视图、viewModel:视图模型

介绍:相对mvc来说,简化了映射关系

介绍2:在MVVM框架下视图和模型是不能直接通信的,只能通过ViewModel进行交互,它能够监听到数据的变化,然后通知视图进行自动更新,而当用户操作视图时,VM也能监听到视图的变化,然后通知数据做相应改动,这实际上就实现了数据的双向绑定。并且VVM可以进行通信。

特点:传统的mvvm要求不能手动去操作dom,vue中有一个ref属性,可以手动操作

优点: 1、有控制器才能做到前后端分离 2、不用频繁的将数据发给后端

(1) MVVM和MVC的区别

MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用。

5、vue和react(v层)

1、库和框架的区别? 库:我们用户主动调用库中的方法,(vue)框架的特点我们被动的被别人调用,写vue的时候要按照别人的规则写在对应的地方才能实现功能,(渐进式的概念就是可以自由组合功能)

6、请说一下Vue2及Vue3响应式数据的理解

原理1: 响应式数据的核心就是数据变化了我能知道,对象在Vue2中采用了defineProperty,将数据定义成了响应式的数据(拦截了所有的属性增加了getter和setter),Vue3中采用了proxy直接可以对对象拦截,不用重写get和set的方法,性能高,不需要直接递归。对数组并没有采用defineProperty因为数组很长,但是不会操作索引更改数据。

原理2: Vue 会遍历 data 数据对象,使 Object.defineProperty() 将每个属性都转换为 getter/setter。每个 Vue 组件实例都有一个对应的 watcher 实例,在组件初次渲染(render)时,会记录组件用到了(调用 getter)哪些数据。当数据发生改变时,会触发 setter 方法,并通知所有依赖这个数据的 watcher 实例,然后 watcher 实例调用对应组件的 render 方法,生成一颗新的 vdom 树,Vue 会将新生成的 vdom 树与上一次生成的 vdom 树进行比较(diff),来决定具体要更新哪些 dom。

缺点:要递归构建,不存在的属性无法被监控到。

如何解决缺陷:

  • Vue2中减少层级数据嵌套不要过深
  • 如果不需要响应式的数据就不要放在data中。
  • 尽量缓存使用过的变量(避免频繁调用get和set)。 image.png

vue双向绑定 当用户输入内容的时触发事件将内容传给对象属性, 由于vue使用了Object.defineProperty劫持了那个对象的属性, 当属性发生改变时就会把数据交给要展示的标签

缺点: 1、对于数组而言,大部分操作都是拦截不到的,只是 Vue 内部通过重写函数的方式解决了这个问题。

vue 为什么data是一个函数: 使用了闭包的设计,为了让每一个组件都有自己的私有作用域,确保各组件数据不会相互干扰

7、react的响应式数据的理解

React 必须显式调用 setState() 方法更新状态,状态更新之后,组件也会重新渲染。

Vue 和 React 在状态更新之后,都会生成一颗新的虚拟 dom 树,与上一颗虚拟 dom 树进行比较(diff),找出其中的差异,再更新真实 dom。

8、Vue中如何检测数组变化?

  • vue2中并没有使用defineProperty来检测我们的数组(性能差,例:如果数组有一万个元素,难道全部遍历一遍),vue2里面就采用重写数组的方式实现,通过原型链+函数劫持的方式实现的(缺陷是不饿能检测到索引更改和数组长度的更改)数组中的元素也会被再次观测

9、Vue中如何进行依赖收集?(观察者模式)

  • 依赖收集的目的是,等会数据变化了可以更新视图,如何收集的,每个属性都是一个dep(dep:订阅器)属性、每个对象也都有一个dep属性,每个组件在渲染的过程中都会创建一个渲染watcher(watcher有三种,渲染watcher,计算性watcher,用户watcher),一个属性可能会有多个watcher,反过来一个watcher有多个dep。
  • 当调用取值方法的时候如果有watcher就会将watcher收集起来,等会数据变化后会通知自己对应的dep触发更新调用watcher。update方法

10、如何理解Vue中模板编译原理

(模板编译原理的核心就是 ast-> 生成代码)

  • 会将模板变成ast语法树
  • 对ast语法进行优化,标记静态节点(vue3中模板编译做了哪些优化 patchFlag,blockTree,事件缓存,节点缓存...)
  • 代码生成,拼接render函数字符串 + new Function + with

11、Vue生命周期钩子是如何实现的

  • 生命周期钩子在内部会被vue维护成一个数组(vue内部有一个方法 mergeOptions)和全局的生命周期合并最终转换成数组,当执行到具体流程时会执行钩子(发布订阅模式),callHook来实现调用

12、Vue的生命周期方法有哪些?一般在哪一步发送请求及原因

  • 在哪里发起请求都可以,主要看你做什么事情。我再reated中和mounted中有区别吗?区别不大,但是如果同步操作created中式无法获取dom中.
  • 在服务端渲染的时候,我们无法使用浏览器的钩子(服务端渲染时把结果渲染成一个字符串,返回给浏览器,渲染过程时在服务器做的,会把功能写在created里)vue3中我们发请求可以全部在mounted中进行
  • ajax肯定会等待你的同步代码都执行完毕,才能拿到结果

13、Vue组件data为什么必须是个函数?

解释1: 1、 因为内部会调用Vue.extend会将组件的定义传入,此时会将用户的参数进行合并检测data属性,如果data不是函数会报警告。 会将当前定义的data合并到组件的内部,如果data是一个对象就存在数据被共享的可能

解释2:

  • vue中组件是用来复用的,为了防止data复用,将其定义为函数。
  • vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。

14、nextTick在哪里使用?原理是? *

  • nextTick功能是批量处理,多次调用默认会将逻辑暂存到队列中,稍后同步代码执行完毕后会采用,同步的方式依次刷新队列(nextTick本身内部采用了异步方法,但是执行逻辑的时候采用的是同步)
  • 内部实现原理(异步的实现原理,先采用promise.then,不行再采用mutationObserver,不行再采用setImmediate,不行再采用setTimeout,优雅降级)

15、computed和watch区别 *

解释1

  • 先说这两个东西内部都是基于watcher的,区别是computed数据可以用于页面渲染,watch不行,computed只有在取值时才会执行对应的回调(lazy为true所以不会立即执行),watch默认会执行一次(拿到老的值)。computed用了一个dirty属性实现了缓存机制,多次取值如果依赖的值不发生变化不会更改dirty的结果,拿到的就是老的值

解释2

1、computed:

  • 支持缓存,只有依赖数据发生改变,才会重新进行计算;

  • 不支持异步,当内有异步操作时无效,无法监听数据的变化;

  • computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的。也就是基 于 data 中声明过或者父组件传递的 props 中的数据通过计算得到的值;

  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性 是一个多对一或者一对一,一般用computed;

  • 如果 computed 属性值是函数,那么默认会走 get 方法,函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个 set 方法,当数据变化时,调用 set 方法;

2、watch

  • 不支持缓存,数据变化,直接会触发相应的操作;

  • watch 支持异步操作;

  • 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
    当一个属性发生变化时,需要执行对应的操作,一对多;

  • 监听数据必须是 data 中声明过或者组合式api中声明的响应式值或者父组件传递过来的 props 中的数据。当数据变化时触发其他操作,函数有两个参数:

16、Vue.set方法时如何实现的? *

为了实现给以前不存在的对象添加属性可以实现更新页面,对象采用的是defineProperty不存在的属性检测不到,数组没检测索引所以也监控不到,

  • Vue({},'name',1);对象本身得是响应式的,如果对象是响应式那么对象本身就会有一个dep属性,我新增属性后触发dep对应的watcher不就OK了,
  • 针对数组内部会调用splice方法,针对对象调用defineReactive方法并且手动notify

17、Vue为什么需要虚拟DOM

  • 最核心的是跨端,不同的平台实现方案不同。内部实现可以不局限于针对浏览器平台
  • 如果开发者频繁操作dom可能会浪费性能,虚拟DOM你可以认为增加了一层缓存,我们会先更新虚拟DOM,在更新到页面上
  • 因为domdiff比较的是前后的虚拟DOM

18、Vue中diff算法原理

  • diff算法是O(n)【O(n)的含义就是只执行一次】级别的,采用的是同级比较,内部是深度优先(深度优先:就是先子节点再到父节点的方式)遍历的方式遍历节点
  • 节点判断是否是同一个元素,如果是同一个元素,则比对属性子集,如果不是则直接删除老的换成新的
  • Vue2中采用了双指针对一些场景做了优化策略(如果是静态节点可以跳过diff算法)
  • 头头,尾尾,尾头,头尾进行优化
  • 最后乱序比较就是根据老节点创造一个映射表,用新的去里边找能复用的就是复用节点(乱序的时候可能中间的顺序是固定的但是都会做一次移动)

vue3里面还有一个blockTree概念,如果是通过模板编译的,会把dymanicChildren组成数组直接数组比对,性能更好,如果不能使用这种方式才采用下面的全量对比(v-for) vue3优化移动节点的时候采用了最长递增子序列来实现,贪心+二分查找+前驱节点实现的,O(nlogn)

19、请说明Vue中key的作用和原理,谈谈你对它的理解

  • key的作用是为了标识唯一性,在diff算的时候可以进行复用。判断是否是相同节点(tag,key)。key尽量在动态列表中不要使用索引(如果使用的是索引,相当于就是没写key),可能会导致更新出问题。(如果是死的列表可以使用索引作为key)

20、谈一谈对Vue组件化的理解

组件化最早出现在webComponent浏览器可以实现自定义标签,兼容性差。组件化的好处就是(为了能实现组件级更新,合理规划代码,复用性强,单向数据流) 组件化会常用到一些技术、属性、事件、插槽

21、Vue的组件渲染流程(p4)

www.bilibili.com/video/BV1b5…

22、组件更新流程(p4)

23、Vue中异步组件原理(p4)