zoukankan      html  css  js  c++  java
  • (十二)前端-VUE面试

    Vue相关

    1.vue生命周期

    什么是Vue生命周期?

    Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期

    Vue****生命周期的作用是什么?

    它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑

    Vue****生命周期总共有几个阶段?

    它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后

    第一次页面加载会触发哪几个钩子?

    第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

    DOM****渲染在哪个周期中就已经完成?

    DOM 渲染在 mounted 中就已经完成了

    每个生命周期适合哪些场景?

    生命周期钩子的一些使用方法:

    beforecreate : 可以在这加个loading事件,在加载实例时触发

    created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用

    mounted : 挂载元素,获取到DOM节点

    updated : 如果对数据统一处理,在这里写上相应函数

    beforeDestroy : 可以做一个确认停止事件的确认框

    nextTick : 更新数据后立即操作dom

    · beforeCreate阶段:vue实例的挂载元素el和数据对象data都是undefined,还没有初始化。

    · created阶段:vue实例的数据对象data有了,可以访问里面的数据和方法,未挂载到DOM,el还没有

    · beforeMount阶段:vue实例的el和data都初始化了,但是挂载之前为虚拟的dom节点

    · mounted阶段:vue实例挂载到真实DOM上,就可以通过DOM获取DOM节点

    · beforeUpdate阶段:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器

    · updated阶段:虚拟DOM重新渲染和打补丁之后调用,组成新的DOM已经更新,避免在这个钩子函数中操作数据,防止死循环

    · beforeDestroy阶段:实例销毁前调用,实例还可以用,this能获取到实例,常用于销毁定时器,解绑事件

    · destroyed阶段:实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁

    2.v-show与v-if区别

    v-show是css切换,v-if是完整的销毁和重新创建

    使用 频繁切换时用v-show,运行时较少改变时用v-if

    v-if=‘false’ v-if是条件渲染,当false的时候不会渲染

    3.MVVM相关

    vue采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty劫持data属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

    MVVM

    M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑

    V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来

    VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View

    ![image.png](file:///C:/Users/admin/AppData/Local/Temp/msohtmlclip1/01/clip_image024.png)

    · View 接收用户交互请求

    · View 将请求转交给ViewModel

    · ViewModel 操作Model数据更新

    · Model 更新完数据,通知ViewModel数据发生变化

    · ViewModel 更新View数据

    MVC

    · View 接受用户交互请求

    · View 将请求转交给Controller处理

    · Controller 操作Model进行数据更新保存

    · 数据更新保存之后,Model会通知View更新

    · View 更新变化数据使用户得到反馈

    ![image.png](file:///C:/Users/admin/AppData/Local/Temp/msohtmlclip1/01/clip_image026.png)

    **
    MVVM****模式和MVC有些类似,但有以下不同**

    · ViewModel 替换了 Controller,在UI层之下

    · ViewModel 向 View 暴露它所需要的数据和指令对象

    · ViewModel 接收来自 Model 的数据

    概括起来,MVVM是由MVC发展而来,通过在Model之上而在View之下增加一个非视觉的组件将来自Model的数据映射到View中。

    4.说说你对 SPA 单页面的理解,它的优缺点分别是什么?

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

    优点:

    · 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;

    · 基于上面一点,SPA 相对对服务器压力小;

    · 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

    缺点:

    · 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;

    · 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;

    · SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

    5、computed 和 watch 的区别和运用的场景?

    computed****: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;

    watch****: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

    运用场景:

    · 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;

    · 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

    computed****的原理

    computed 本质是一个惰性求值的观察者。

    computed 内部实现了一个惰性的 watcher,也就是 computed watcher,computed watcher 不会立刻求值,同时持有一个 dep 实例。

    其内部通过 this.dirty 属性标记计算属性是否需要重新求值。

    当 computed 的依赖状态发生改变时,就会通知这个惰性的 watcher,

    computed watcher 通过 this.dep.subs.length 判断有没有订阅者,

    有的话,会重新计算,然后对比新旧值,如果变化了,会重新渲染。 (Vue 想确保不仅仅是计算属性依赖的值发生变化,而是当计算属性最终计算的值发生变化时才会触发渲染 watcher 重新渲染,本质上是一种优化。)

    没有的话,仅仅把 this.dirty = true。 (当计算属性依赖于其他数据时,属性并不会立即重新计算,只有之后其他地方需要读取属性的时候,它才会真正计算,即具备 lazy(懒计算)特性。)

    6.v-model 的原理

    我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

    · text 和 textarea 元素使用 value 属性和 input 事件;

    · checkbox 和 radio 使用 checked 属性和 change 事件;

    · select 字段将 value 作为 prop 并将 change 作为事件。

    <input v-model='something'>
        
    相当于
     
    <input v-bind:value="something" v-on:input="something = $event.target.value">
    

    ![img](file:///C:/Users/admin/AppData/Local/Temp/msohtmlclip1/01/clip_image028.png)

    7.VUE和REACT 的区别?

    react整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中,是单向数据流;

    vue的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom。

    核心思想:

    vue的整体思想仍然是拥抱经典的html(结构)+css(表现)+js(行为)的形式,vue鼓励开发者使用template模板,并提供指令供开发者使用(v-if、v-show、v-for等等),因此在开发vue应用的时候会有一种在写经典web应用(结构、表现、行为分离)的感觉。另一方面,在针对组件数据上,vue2.0通过Object.defineProperty对数据做到了更细致的监听,精准实现组件级别的更新。

    react整体上是函数式的思想,组件使用jsx语法,all in js,将html与css全都融入javaScript,jsx语法相对来说更加灵活,我一开始刚转过来也不是很适应,感觉写react应用感觉就像是在写javaScript。当组件调用setState或props变化的时候,组件内部render会重新渲染,子组件也会随之重新渲染,可以通过shouldComponentUpdate或者PureComponent可以避免不必要的重新渲染(个人感觉这一点上不如vue做的好)。

    具体可参考掘金文章(关于Vue*和React*的一些对比及个人思考:https://juejin.im/post/5e153e096fb9a048297390c1*)*

    8. 为什么在 Vue3.0 采用了 Proxy,抛弃Object.defineProperty?

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

    Proxy 可以劫持整个对象,并返回一个新的对象。Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。

    Proxy 的优势如下:

    · Proxy 可以直接监听对象而非属性;

    · Proxy 可以直接监听数组的变化;

    · Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;

    · Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;

    · Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

    Object.defineProperty 的优势如下:

    · 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

    9. Vue 组件 data 为什么必须是函数 ?

    因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。

    所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。new Vue 的实例是不会被复用的,因此不存在以上问题。

    10、谈谈你对 keep-alive 的了解?

    keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:

    o 一般结合路由和动态组件一起使用,用于缓存组件;

    o 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;

    o 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

    11、Vue 组件间通信有哪几种方式?

    (1)**props / $emit** 适用 父子组件通信

    这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。

    (2)**ref** **$parent / $children** 适用 父子组件通信

    · ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

    · $parent / $children:访问父 / 子实例

    (3)**EventBus** ``**(**``**$emit / $on**``**)** 适用于 父子、隔代、兄弟组件通信

    这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件

    (4)**$attrs**/**$listeners** 适用于 隔代组件通信

    · $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。

    · $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

    (5)**provide / inject** 适用于 隔代组件通信

    祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

    (6)Vuex 适用于 父子、隔代、兄弟组件通信

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

    · Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

    · 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

    12.请介绍一下你对vuex的理解?

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

    (1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

    (2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

    主要包括以下几个模块:

    · State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。

    · Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。

    · Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。

    · Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。

    · Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

    VUEX****实现原理? (课程中的代码)

    13.请介绍一下你对vue-router的理解?

    vue-router****实现原理? (课程中的代码)

    vue-router 有 3 种路由模式:hash、history、abstract,

    l hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;

    l history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;

    l abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.

    1****)hash 模式的实现原理

    早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search':

    hash 路由模式的实现主要是基于下面几个特性:

    l URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;

    l hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;

    l 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;

    l 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

    (2)history 模式的实现原理

    HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

    window.history.pushState(null, null, path);
    window.history.replaceState(null, null, path);
    

    history 路由模式的实现主要基于存在下面几个特性:

    l pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;

    l 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);

    l history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

    导航钩子函数(导航守卫)?

    l 全局守卫

    1. router.beforeEach 全局前置守卫 进入路由之前

    2. router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用

    3. router.afterEach 全局后置钩子 进入路由之后

    // main.js 入口文件
        import router from './router'; // 引入路由
        router.beforeEach((to, from, next) => { 
          next();
        });
        router.beforeResolve((to, from, next) => {
          next();
        });
        router.afterEach((to, from) => {
          console.log('afterEach 全局后置钩子');
        });
     
    

    l 路由独享的守卫 你可以在路由配置上直接定义 beforeEnter 守卫

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => {
            // ...
          }
        }
      ]
    })
    

    l 组件内的守卫 你可以在路由组件内直接定义以下路由导航守卫

    const Foo = {
      template: `...`,
      beforeRouteEnter (to, from, next) {
        // 在渲染该组件的对应路由被 confirm 前调用
        // 不!能!获取组件实例 `this`
        // 因为当守卫执行前,组件实例还没被创建
      },
      beforeRouteUpdate (to, from, next) {
        // 在当前路由改变,但是该组件被复用时调用
        // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
        // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
        // 可以访问组件实例 `this`
      },
      beforeRouteLeave (to, from, next) {
        // 导航离开该组件的对应路由时调用,我们用它来禁止用户离开
        // 可以访问组件实例 `this`
        // 比如还未保存草稿,或者在用户离开前,
        将setInterval销毁,防止离开之后,定时器还在调用。
      }
    }
    

    14、Vue 中的 key 有什么作用?

    Vue 中 key 的作用是:key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速

    更准确:因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。

    更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

    15.ref的作用

    1. 获取dom元素this.$refs.box

    2. 获取子组件中的datathis.$refs.box.msg

    3. 调用子组件中的方法this.$refs.box.open()

    30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    面试完50个人后我写下这篇总结

    公司要求会使用框架vue,面试题会被问及哪些?

    [Vue 项目性能优化 — 实践指南](

    ---------------------------
    作者:HelloBytes
    关于作者: JavaEE小新人,请多多赐教!
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    fedora上部署ASP.NET——(卡带式电脑跑.NET WEB服务器)
    SQL Server 请求失败或服务未及时响应。有关详细信息,请参见事件日志或其它适合的错误日志
    8086CPU的出栈(pop)和入栈(push) 都是以字为单位进行的
    FTP 服务搭建后不能访问问题解决
    指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
    Linux 安装MongoDB 并设置防火墙,使用远程客户端访问
    svn Please execute the 'Cleanup' command. 问题解决
    .net 操作MongoDB 基础
    oracle 使用绑定变量极大的提升性能
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
  • 原文地址:https://www.cnblogs.com/HelloBytes/p/14177977.html
Copyright © 2011-2022 走看看