番外01:前端八股文面试题-Vue篇

一:Vue基础

1.Vue的基本原理 

一个Vue实例创建 🔜 遍历data中的属性 🔜 通过defineProperty/proxy将其转为getter/setter 🔜

在内部追踪相关依赖 🔜 属性被访问和修改时通知变化。

每个组件实例都有响应的watcher程序实例 🔜 watcher会在组件渲染过程中把属性记为依赖 🔜 依赖被setter调用,watcher重新计算 🔜 相关联的组件更新。

2.双向数据绑定的原理

数据劫持 + 发布者-订阅者模式

(1)Observer对数据对象进行遍历 🔜 为其加上getter/setter 🔜 对象的某个值赋值会触发setter

🔜 监听到数据变化。

(2)compile解析模板指令,将变量替换成数据 🔜 初始化渲染页面视图 🔜 指令对应的节点绑定更新函数 🔜  添加监听数据订阅者 🔜 数据变动,收到通知,更新视图。

(3)Watcher是Observer和Compile之间通信的桥梁:

        01:自身实例化时往属性订阅器(dep)中添加自己

        02:自身有一个update方法

        03:属性变动dep.notice()通知时,调用自身的update()方法,触发Compile中绑定的回调

(4) MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer监听自己的model数据变化 🔜 通过Compile来解析编译模板指令 🔜 最终利用Watcher搭起Observer和Compile之间通信的桥梁。

3、使用Object.defineProperty()来进行数据劫持有什么缺点

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

在 Vue3.0 中已经不使用这种方式了,而是通过使用 Proxy 对对象进行代理,从而实现数据劫持。使用Proxy 的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法。

注解:通过下标方式修改数据或者给对象新增属性,都不能触发组件的重新渲染。

4、MVC和MVVM的区别

(1)MVC

通过分离Model、View和Controller的方式来组织代码结构。

View负责页面的显示逻辑 🔜 Model负责存储页面的业务数据,以及相应数据的操作🔜 Controller层是View层和Model层的纽带。

(2)MVVM 

MVVM分为Model、View、ViewModel

      01:Model代表数据模型,数据和业务逻辑都在Model层中定义;

      02:View代表UI视图,负责数据的展示;

      03:ViewModel负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作;

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

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

5、Computed和Watch的区别

(1)Computed:

        01:支持缓存,只有依赖的数据发生了变化,才会重新计算

        02:不支持异步,Computed中有异步操作,无法监听数据变化

        03:值会默认走缓存,计算属性是基于响应式依赖进行缓存的,基于data或父组件传递过来的props中的数据进行计算。

        04:一个属性依赖其余属性,一般会使用computed

        05:computed属性的属性值是函数,默认使用get方法,函数的返回值就是属性的属性值。?

(2)Watch:

        01:不支持缓存,数据变化时,就会触发相应的操作

        02:支持异步监听

        03:监听接收两个参数,一个是最新的值,一个是变化之前的值

        04:监听数据必须是data或父组件传递过来的prop

        05:immedate:组件立即触发回调函数 deep:深度监听(deep无法监听数组和对象内部的变化?)

6、Computed和Methods的区别?

可以将同一函数定义为一个 method 或者一个计算属性。对于最终的结果,两种方式是相同的

不同点:

  • computed: 计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值;
  • method 调用总会执行该函数。

7:slot是什么?有什么作用?原理是什么?

slot又名插槽 🔜 Vue的内容分发机制 🔜 组件内部的模板引擎使用slot元素作为承载分发内容的出口。

slot分为三类:默认插槽、具名插槽、作用域插槽:

        (1)默认插槽:匿名插槽,slot没有指定name属性值时一个默认显示的插槽,一个组件内只有一个默认插槽。

        (2)具名插槽:带有name属性的slot 🔜 一个组件可以出现多个具名插槽

        (3) 作用域插槽:默认插槽和具名插槽的一个变体 🔜 其可以将子组件内部的数据传递给父组件。

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在 vm.$slot中,默认插槽为 vm.$slot.default,具名插槽为 vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用 $slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

8:如何保存页面当前的状态

(1)将状态存储在LocalStorage/SessionStorage中

(2)路由传值

(3)使用keep-alive来缓存页面?

9:常见的事件修饰符及其作用

(1)​.stop​:等同于 JavaScript 中的 ​event.stopPropagation()​ ,防止事件冒泡;

(2)​.prevent​ :等同于 JavaScript 中的 ​event.preventDefault()​ ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);

(3)​.capture​ :与事件冒泡的方向相反,事件捕获由外到内;

(4)​.self​ :只会触发自己范围内的事件,不包含子元素;

(5)​.once​ :只会触发一次。

10:v-show和v-if的原理及区别

(1)原理

v-if调用addIfCondition方法,生成vnode的时候会忽略对应节点,render的时候就不会渲染。

v-show会生成v-node,render的时候也会渲染成真实节点 🔜 render过程中会在节点属性中修改show属性值,也就是常说的display

(2)区别

        01:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐。

        02:v-if有更高的切换消耗;v-show有更高的初始渲染消耗

        03:v-if适合运营条件不大可能改变;v-show适合频繁切换。

11:data为什么是一个函数而不是对象

JavaScript中的对象是引用类型的数据 🔜 多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其余实例中的数据也会发生变化 🔜 会使得复用组件时,组件之间相互干扰。

数据以函数返回值的形式定义 🔜 每次复用组件时,就会返回一个新的data 🔜 每个组件都有自己的私有数据空间,其各自维护自己的数据,不会干扰其他组件的正常运行。

12:$nextTick原理及作用(具体引用?)

  • 在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构的时候,这个操作就需要方法在 ​nextTick()​的回调函数中。
  • 在vue生命周期中,如果在created()钩子进行DOM操作,也一定要放在 ​nextTick()​的回调函数中。

因为在created()钩子函数中,页面的DOM还未渲染,这时候也没办法操作DOM,所以,此时如果想要操作DOM,必须将操作的代码放在 nextTick()的回调函数中。

13:Vue data中某一个属性的值发生改变之后,视图会立即同步执行重新渲染吗?

不会立即同步执行重新渲染。

Vue实现响应式并不是数据发生变化时立即更新DOM 🔜 Vue更新DOM是异步执行的 🔜 侦听到数据变化,Vue将开启一个队列,并缓存在同一个事件循环中发生的所有数据变更。

同一个watcher被多次触发,只会被推入队列中一次 🔜 下一个事件的循环tick中,Vue刷新队列并执行实际(已去重)的工作。

14:自定义指令?

15:子组件可以直接改变父组件的数据吗?

不可以直接改变父组件的数据。

Vue提倡单向数据流,即父级props的更新会流向子组件,反过来则不行。这样可以防止意外改变父组件的状态,使得应用数据流变得难以理解。

只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改。

16:Vue的优点(背)

  • 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 ​kb ​;
  • 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
  • 双向数据绑定:在数据操作方面更为简单;
  • 组件化:实现了 ​html ​的封装和重用,在构建单页面应用方面有着独特的优势;
  • 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
  • 虚拟DOM:​dom​ 操作是非常耗费性能的,不再使用原生的 ​dom ​操作节点,极大解放 ​dom ​操作,但具体操作的还是 ​dom ​不过是换了另一种方式;
  • 运行速度更快:操作虚拟 ​dom​,就性能而言, ​vue ​存在很大的优势。

17:assets和static的区别

相同点:

assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片、字体图标、样式文件等都可以放在这两个文件下。

不同点:

assets中放的静态资源 🔜 npm run build 🔜 assets中静态资源会进行打包上传。

static中放置的静态资源 🔜 npm run  build 🔜 不会走打包压缩格式化等流程。

建议:

template中的静态资源文件都可以放在assets中,走打包流程,减少体积。

引入的第三方资源文件可以放置在static中,因为第三方文件已经经过了处理。

18:什么是mixin(混入)

(1)mixin使我们能够为Vue组件编写可插拔和可重用的功能

(2)多个组件之间重用一组组件选项,例如生命周期hook,方法等,则可以将其编写为mixin,并在组件中简单引用它。

(3) 然后将mixin内容合并到组件中。mixin中定义的生命周期 🔜 执行时优先于组件自己的hook

19:Vue的模板编译原理

template无法被浏览器解析并渲染 🔜 需要将template转化成一个javaScript函数 🔜 浏览器执行这个函数渲染出对应的HTML元素 🔜 这个过程为模板编译。

三个阶段:解析parse        优化optimize        生成generate        🔜  最终生成可执行函数render

20:Vue的性能优化有哪些

(1)编码阶段

  • 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
  • v-if和v-for不能连用
  • 如果需要使用v-for给每项元素绑定事件时使用事件代理
  • SPA 页面采用keep-alive缓存组件
  • 在更多的情况下,使用v-if替代v-show
  • key保证唯一
  • 使用路由懒加载、异步组件
  • 防抖、节流
  • 第三方模块按需导入
  • 长列表滚动到可视区域动态加载
  • 图片懒加载

(2)SEO优化

  • 预渲染
  • 服务端渲染SSR

(3)打包优化

  • 压缩代码
  • Tree Shaking/Scope Hoisting
  • 使用cdn加载第三方模块
  • 多线程打包happypack
  • splitChunks抽离公共文件
  • sourceMap优化

(4)用户体验

  • 骨架屏
  • PWA
  • 还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。

21:mixin 和 mixins 区别

22:MVVM的优缺点

优点:

        (1)分离视图(View)和模型(Model) 🔜 降低代码耦合 🔜 提高视图或者逻辑的重用性

        (2)提高可测试性:ViewModel的存在可以帮助开发者更好地编写测试代码

        (3)自动更新dom:双向绑定 🔜 数据更新后视图自动更新

缺点:

        (1)Bug很难调试

        (2)大的模块,model也会很大 🔜 长期持有,不释放内存 🔜 会花费更多的内存

        (3)大型的图形应用程序,视图状态较多 🔜 ViewModel的构建和维护成本较高

二:Vue的生命周期

1:简单说一下Vue的生命周期

        (1)beforeCreate(创建前):数据观测、初始化事件还未开始 🔜 data的响应式追踪、event\watcher还未被设置 🔜 不能访问data|computed|watch|methods中的数据。

        (2)created(创建后):实例创建完成 🔜 实例上配置的options包括data、computed、watch、methods等都配置完成 🔜 渲染的节点还未挂载到DOM,所以不能访问$el属性。

        (3)beforeMount(挂载前): 挂载开始之前被调用,相关的render函数首次被调用 🔜 实例完成以下的配置:编译模板 🔜 把data里面的数据和模板生成html 🔜 此时还未挂载html到页面上。

        (4)mounted(挂载后):在el被新创建的 vm.$el 替换,并挂载到实例上去之后调用。

实例完成以下配置:编译好的html内容替换el属性指向的dom对象 🔜 完成模板中的html渲染到html页面中 🔜 此过程进行ajax交互。

        (5)beforeUpdate(更新前):响应式数据更新时调用。响应式数据更新 🔜 真实的DOM还没有被渲染。

        (6)update(更新后):在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。

        (7)beforeDestroy(销毁前):实例销毁之前调用。实例仍然可用 🔜 this仍能获取到实例

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

另外还有 keep-alive 独有的生命周期,分别为 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 activated 钩子函数。

2:Vue子组件和父组件执行的顺序

加载渲染过程:

1.父组件 beforeCreate

2.父组件 created

3.父组件 beforeMount

4.子组件 beforeCreate

5.子组件 created

6.子组件 beforeMount

7.子组件 mounted

8.父组件 mounted

更新过程:

1. 父组件 beforeUpdate

2.子组件 beforeUpdate

3.子组件 updated

4.父组件 updated

销毁过程:

1. 父组件 beforeDestroy

2.子组件 beforeDestroy

3.子组件 destroyed

4.父组件 destoryed

3:Created和mounted的区别

  • created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
  • mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

4:一般在哪个生命周期请求异步数据

可以在created、beforeMount、mounted中进行调用 🔜 三个钩子函数中,data已经创建 🔜 可以将服务端返回的数据进行赋值。

推荐在created钩子函数中调用异步请求:

        (1)更快速获取到服务端数据,减少页面加载时间,用户体验更好。

        (2)SSR不支持beforeMount、mounted钩子函数,放在created中有助于一致性。

5:keep-alive中的生命周期哪些

keep-alive 🔜 Vue提供的一个内置组件,用来对组件进行缓存 🔜 组件切换过程中,防止重复渲染dom

包裹了keep-alive的组件 🔜 多出两个生命周期:deactivated、activated 🔜 beforeDestroy 和destroyed 不会被触发,组件不会真正的销毁。

三:组件通信方式

1:props/$emit

父组件通过props向子组件传递数据,子组件通过$emit和父组件通信

(1)父组件向子组件传值,props使得父子组件之间形成了一个单向下行绑定,子组件的数据会随着父组件不断更新。

(2) 可以显示定义一个或一个以上的数据 🔜 接收的数据可以是各种数据类型 🔜 也可以传递一个函数。

(3)属性命名规则 🔜 驼峰形式

子组件向父组件传值

$emit绑定一个自定义事件 🔜 事件执行 🔜 参数传递给父组件 🔜 父组件通过v-on监听接收参数

2:eventBus事件总线($emit/$on)

eventBus事件总线适用于父子组件,非父子组件等之间的通信。

3:依赖注入(project/inject)

Vue中的依赖注入 🔜 层数很深的情况下进行传值,不用一层一层传递

        project:钩子用来发送数据和方法

        inject:钩子用来接收数据和方法

4:ref/$refs

实现父子组件之间的通信

ref:属性用于子组件 🔜 指向自组建的实例 🔜 通过实例访问子组件的数据和方法

5:$parent / $children

        $parent 可以让组件访问父组件的实例

        $children 可以让组件访问子组件的实例 🔜 不能保证顺序 🔜 数据不是响应式的

6:$attrs / $listeners

组件之间跨代通信

四:路由

1:Vue-Router的懒加载如何实现

const List = () => import('@/components/list.vue')

2:路由的hash和history模式的区别(?)

(1)hash模式

简介: 开发中的默认模式 🔜 URL中带着# 🔜 http://www.abc.com/#/vue 🔜 hash值是#/vue

特点:hash值出现在URL里 🔜 不会在HTTP请求中 🔜 改变hash值,不会重新加载页面

原理:hash模式的主要原理 🔜 onhashchange()事件

window.onhashchange = function(event){
    console.log(event.oldURL, event.newURL);
    let hash = location.hash.slice(1);
}

(2)history模式

简介:URL中没有# 🔜 传统的路由分发模式 

特点:history模式需要后台支持 🔜 后台没有正确配置,返回404

API:其api分为两部分,切换历史状态和修改历史状态

3:如何获取页面的hash变化

(1)监听$route的变化

// 监听,当路由发生变化的时候执行
watch: {
  $route: {
    handler: function(val, oldVal){
      console.log(val);
    },
    // 深度观察监听
    deep: true
  }
},

(2)window.location.hash读取#值

window.location.hash 的值可读可写,读取来判断状态是否改变,写入时可以在不重载网页的前提下,添加一条历史访问记录。

4:$route和$router的区别

        (1)$ route是“路由信息对象” 🔜 path、params、hash、query等路由信息参数

        (2)$router是“路由实例”对象 🔜 包括了路由的跳转方法,钩子函数等

五:VueX

1:VueX的原理

状态管理模式 🔜 应用核心:store(库)🔜 store基本上就是一个容器,包含着应用中的大部分状态。

        (1)状态存储是响应式 

        (2)显式的提交(commit)mutation 🔜 改变store中的状态

 (1)核心流程中的主要功能

        - 组件会触发(dispatch)一些事件或动作

        - 组件发出动作,目的是获取/改变数据 🔜 VueX数据是集中管理的,不能直接改变数据 🔜需要(Commit)到Mutations中

        - Mutation中更改state中的数据

        - State中的数据改变 🔜 重新渲染(Render)到Vue Component中

(2)各模块在核心流程中的主要功能(Vuex有哪几种属性)

        - Vue Components:Vue组件

        - dispatch:操作行为触发防范,唯一能执行action的方法

        - actions:操作行为处理模块,包含同步 / 异步操作,支持多个同名方法,按照注册的顺序依次触发。

        - commit:状态改变提交操作方法。对mutation进行提交 🔜 唯一能执行mutation的方法

        - mutations:状态改变操作方法。Vuex修改state的唯一推荐方法 🔜只能进行同步操作 🔜 方法名全局唯一。

        - state:页面状态管理容器对象。集中存储Vuecomponents中data对象的零散数据,全局唯一。

        - getters:state对象读取方法。

2:Vuex中action和mutation的区别

(1)mutation

        1):一系列的同步函数,修改state中变量的状态。

        2):需要通过commit来提交需要操作的内容。

(2)action

        1):Action可以包含任意异步操作

        2):Action提交的mutation,而不是直接变更状态

(3)不同点

        1):Mutation专注于修改State,理论上是修改State的唯一途径;Action业务代码、异步请求

        2):必须同步执行;Action:可以异步,但不能直接操作State

        3):在视图更新时,先触发actions,actions再触发mutation

        4):mutation的参数是state,它包含store中的数据;store的参数是context,它是 state 的父级,包含 state、getters。

3:Vuex和localStorage的区别

(1)最重要的区别

        - vuex存储在内存中

        - localstorage则以文件的方式存储在本地 🔜 只能存储字符串类型的数据

        - Vuex能做到数据的响应式,localstorage不能

(2)永久性

        - 刷新页面时,Vuex存储的值会丢失,localstorage不会

4:Vuex和单纯的全局对象有什么区别

        

好的,我会尽力回答你的问题。以下是前端Vue面试八股文: 1. Vue的生命周期有哪些?它们分别在什么时候触发? 答:Vue的生命周期分为8个阶段,分别是:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。它们的触发顺序如下: beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed 2. Vue组件之间如何通信? 答:Vue组件之间通信有以下几种方式: (1)props/$emit:父组件通过props向子组件传递数据,子组件通过$emit触发事件向父组件传递数据。 (2)$parent/$children:通过$parent/$children访问父/子组件实例,从而进行数据传递。 (3)$refs:通过$refs访问子组件实例,从而进行数据传递。 (4)event bus:通过事件总线来进行组件之间的通信。 (5)Vuex:使用Vuex来进行全局状态管理。 3. Vue中的路由是什么?如何实现路由跳转? 答:Vue中的路由是指根据不同的URL地址展示不同的内容。Vue中可以使用vue-router来实现路由功能。实现路由跳转可以使用以下两种方式: (1)使用<router-link>标签来实现路由跳转。 (2)使用$router.push()方法来实现路由跳转。 4. Vue中的computed和watch有什么区别? 答:computed和watch都是Vue中用于监听数据变化的方法,它们的区别如下: (1)computed是计算属性,依赖于其他属性的值,并且computed的值会被缓存,只有当依赖的属性发生变化时才会重新计算。而watch是监听属性的变化,当属性发生变化时会执行回调函数。 (2)computed适用于计算复杂的属性,而watch适用于监听某个属性的变化并执行相应的操作。 5. Vue中的v-model指令是什么?如何使用? 答:v-model指令是Vue中用于实现双向数据绑定的指令。它可以将表单元素的值与Vue实例中的数据进行绑定,从而实现数据的自动同步。使用v-model指令可以将表单元素的值与Vue实例中的数据进行绑定,例如: <input v-model="message" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值