如果准备一场vue面试

2022/11/8 Vue

# 对SSR的理解

SSR页就是服务端渲染,也就是将Vue客户端把渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端

SSR的优势:

  • 更好的SEO
  • 首屏加载速度更快

SSR的缺点

  • 开发条件会受到限制,服务器端渲染只支持beforeCreate和create两个钩子;
  • 当需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于NODE.js环境;
  • 更多的服务端负载.

# Vue的优点

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

# computed的实现原理

  1. computed 本质是一个惰性求值的观察者
  2. computed 内部实现了一个惰性的watcher,也就是computed watcher,computed watcher 不会立刻求值,同时持有一个dep示例.
  3. 其内部通过this.dirty属性标记计算属性是否需要重新求值.
  4. 当computed的依赖状态发生改变时,就会通知这个惰性的watcher,computed watcher通过 this.dep.subs.length判断有没有订阅者,
  5. 有的话,会重新计算,然后对比新旧值,如果变化了,才会重新渲染,(Vue想确保不仅仅是计算属性依赖的值发生变化,而是当计算属性最终计算的值发生变化时才会触发渲染watcher重新渲染,本质上是一种优化.)
  6. 没有的话,仅仅把this.dirty = true.(当计算属性依赖于其他数据时,属性并不会立即重新计算,只有之后其他地方需要读取属性的时候,他才会真正的计算,寄具备lazy(懒计算)特性.)

# 能说下vue-router中常用的hash和history路由模式的实现原理吗?

  1. hash模式的实现原理 早期的前端路由实现就是基于localhost.hash来实现的,其实现原理很简单,localhost.hash的值就是URL中#后面的内容.比如https://www.baidu.com#search,它的localhost.hash的值为‘#search’ hash路由模式的实现主要是基于下面几个特性:
    • URL中的hash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash部分不会被发送;hash值的改变,都会在浏览器的访问历史中增加一个记录,因此我们能通过浏览器的回退、前进按钮控制hash的切换‘
    • 可以通过a标签,并设置href属性,当用户点击这个表亲啊后,URL的hash值会发生改变;或者使用javascript来对localhost.hash进行赋值,改变URL的hash值;
    • 我们可以使用hashchange事件来监听hash的变化,从而对页面进行跳转(渲染);
  2. history模式的实现原理 HTML5提供了Histoty API来实现URL的变化,其中最主要的两个API有以下两个: history.pushState()和history.replaceState().这两个API可以在不进行刷新的情况下,操作浏览器的历史记录.唯一不同的时,前者是增加一个历史记录,后者是直接替换当前的历史记录,如下所示:
    window.history.pushState(null,null,path);
    window.history.repalceState(null,null,path);
    
    1
    2
    history 路由模式的实现主要基于存在下面几个特性:
    • pushState 和replaceState 两个API来操作实现URL的变化;
    • 我们可以使用popstate事件来监听url的变化,从而对页面进行跳转(渲染);
    • history.pushState()或history.replaceState()不会出发popstate事件,这时候我们需要手动触发页面跳转(渲染);
      参考:前端vue面试题详细解答 (opens new window)

# 对React和Vue的理解,它们的异同

  • 相似之处:
    • 都将注意力集中保持在核心库,而将其他功能如路由和全局状态管理相关的库;
    • 都有自己的构建工具,能让你得到一个根据最佳实践设置的项目模版;
    • 都使用了virtual DOM (虚拟DOM)提高重绘性能;
    • 都有props的概念,允许组件间的数据传递;
    • 都鼓励组件化应用,将应用分拆成一个个功能明确的模块,提高复用性;.
  • 不同之处:
    1. 数据流 Vue默认支持数据双向绑定,而React一直提倡单向数据流

    2. 虚拟DOM
      Vue2.x开始引入‘Virtual DOM’,消除了和React在这方面的差异,但是在具体的细节还是有各自的特点.

      • Vue宣称可以更快的计算出 Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.
      • 对于React而言,每当应用的状态被改变时,全部自组件都会重新渲染.当前,这可以通过PureComponent/shouldComponentUpdate这个生命周期方法来进行控制,但Vue将此视为默认的优化.
    3. 组件化
      React与Vue最大的不同是模版的编写.

      • Vue鼓励写近似常规的html模版,写起来很接近标准html元素,只是多写了一些属性.
      • React推荐你所有的模版通用Javascript的语法扩展——JSX书写.
        具体来讲:React中的rrender函数是支持闭包特性的,所以import的组件在render中可以直接调用.但是在Vue中,由于模版中使用的数据都必须在this上进行一次中转,所以import一个组建完了之后,还需要在components中在声明下.
    4. 监听数据变化的实现原理不同

      • Vue 通过getter/setter以及一些函数的劫持,能精确知道数据变化,不需要特变的优化就能达到很好的性能.
      • React默认时通过比较引用的方式进行的,如果不优化(pureComponents/shouldComponentUpdate)可能导致大量不必要的DOM的重新渲染.这是因为Vue使用的是可变数据,而React更强调数据的不可变.
    5. 高阶组件 React可以通过高阶组件(HOC)来扩展,而Vue需要通过mixins来扩展.

      高阶组件就是高阶函数,而React的组件本身就是纯粹的函数,所以高阶函数对React来说易如反掌.相反Vue.js使用HTML模版创建视图组件,这时模版无法有效的变异,因此Vue不能采用HOC来实现.

    6. 构建工具 两者都有自己的构建工具:

      • React==> Create React APP
      • Vue ==> vue-cli
    7. 跨平台

      • React ==> React Native
      • Vue ==> Weex

# Vue 的生命周期方法有哪些 一般在哪一步发请求

# beforeCreate

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

# created

  • 实例已经创建完成之后被调用.
  • 在这一步,实例已经完以下的配置:数据观测(data observer),属性和方法的运算,watch/event事件回调,这里没有$el,如果非想要与DOM交互,可以通过vm.$nextTick来访问DOM.

# befeoreMounted

  • 在挂载之前被调用:相关的render函数首次被调用.

# mounted

  • 在挂载完成后发生,在当前阶段,真实的DOM挂载完毕,数据完成双向绑定,可以访问到DOM节点.

# beforeUpdate

  • 数据更新时调用,发生在虚拟DOM重新渲染和打补丁(patch)之前.可以在这个狗子中进一步的更改状态,这不会出发附加的重新渲染过程

# updated

  • 发生在更新完成之后,当前阶段组件DOM已完成更新.要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器渲染期间不被调用.

# beforeDestroy

  • 实例销毁之前调用.在这一步,实例仍然完全可用.我们可以在这时候进行善后和收尾工作,比如清除定时器.

# destroyed

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

# activated

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

# deactivated

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

异步请求在哪一步发起?

可以在钩子函数create、beforeMount,mounted、中进行异步请求,因为在这三个钩子函数中,data已经创建,可以讲服务端返回的数据进行赋值.

如果异步请求不需要依赖DOM推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下优点:

  • 能更快的获取到服务端的数据,减少页面loading事件;
  • ssr(服务端渲染)不支持beforeMount,mounted钩子函数,所以放在created中有助于一致性;

# Vue路由hash模式和history模式

# hash模式

早期的前端路由实现就是基于localhost.hash来实现的,其实现原理很简单,localhost.hash的值就是URL中#后面的内容.比如https://www.baidu.com#search,它的localhost.hash的值为‘#search’

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

  • URLhash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash部分不会被发送;
  • hash值的改变,都会在浏览器的访问历史中增加一个记录.因此我们能通过浏览器的回退、前进按钮控制hash的切换;
  • 可以通过a标签,并设置href属性,当用户点击这个标签后,URLhash值后发生改变;或者使用javascript来对localhost.hash进行赋值,改变URL的hash值;
  • 我们可以使用hashchange事件来坚挺hash的变化.从而对页面进行跳转(渲染)
window.addEventListener('hashchange',funcRef,false)
1

每一次改变hash(window.localhost.hash),都会在浏览器的访问历史中增加一个记录利用hash的以上特点,就可以来实现前端路由’更新视图但不重新请求页面‘的功能了;

特点 : 兼容性好但不美观;


# history模式

history采用HTML5的新特性;且提供了两个方法:pushState(),repalceState()可以对浏览器历史记录栈进行修改,以及popState()事件的监听到状态变更

window.history.pushState(null,null,path)
window.history.replaceState(null,null,path)
1
2

这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前URL改变了.但浏览器不会刷新页面,这就为单页面应用前端路由‘更新视图但不重新请求页面’提供了基础.

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

  • pushState()replaceState()两个api来操作实现URL 的变化;
  • 我们可以使用popState()事件来监听URL的变化,从而对页面进行跳转(渲染)
  • history.pushState()或history.replace()不会触发popState事件,这时我们需要手动触发页面跳转(渲染)

特点: 虽然美观,但是刷新会出现404,需要后端进行配置

# 什么是MVVM?

Model-View-ViewModel(MVVM)是一个软件架构设计模式,由微软WPF和Silverlight的架构师.....开发,是一种简化用户界面的事件驱动编程方式.由John Gossman()于2005年子啊他的博客上发表

MVVM源自经典的Model-View-Controller(MVC)模式,MVVM的出现促进了前端开发与后端业务逻辑的分离,极大的提高了前端开发效率,MVVM的核心是ViewModel层,它就像是一个中转站,(value Converter),负责转换Model中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与Model层通过接口请求进行数据交互,起承上启下的作用

  1. View层
    1. View 是视图层,也就是用户界面.前端主要是有HTML与CSS来构建.
  2. Model层
    1. Model是指数据模型.泛指后端进行各种业务逻辑处理和数据操控,对于前端来说就是后端提供的api接口.
  3. ViewModel层
    1. ViewModel 是由前端开发人员组织生成和维护的视图数据层.在这一层,前端开发者对从后端获取的Model数据进行转换处理,做二次封装,以生成View层使用预期的视图数据模型.需要注意的是ViewModel所封装出来的数据模型包括视图的状态和行为两部分,而Model层的数据模型指示包含状态的,比如页面的这一块展示什么,而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了ViewModel里.这样的封装使得ViewModel可以完整的去描述View层.
    2. MVVM框架实现了双向绑定,这样ViewModel,的内容会实时展示在View层,前端开发者再也不必低效又麻烦的通过DOM层去更新视图,MVVM框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护ViewModel,更新数据视图就会自动得到相应更新.这样View层展现的不是Model层的数据,而是ViewModel的数据,由ViewModel负责与Model层交互,这样就完全解藕了View和Model层,这个解藕是至关重要的,它是前后端分类方案实施的重要一环.
    3. 我们通过一个Vue实例来说明MVVM的具体实现
      1. View层
        <div id="app">
        <p>{{message}}</p>
        <button v-on:click="showMessage()">Click me</button>
         </div>
        
        1
        2
        3
        4
      2. ViewModel层
        var app = new Vue({
          el: '#app',
          data: {  // 用于描述视图状态   
              message: 'Hello Vue!', 
          },
          methods: {  // 用于描述视图行为  
              showMessage(){
                  let vm = this;
                  alert(vm.message);
              }
          },
          created(){
              let vm = this;
              // Ajax 获取 Model 层的数据
              ajax({
                  url: '/your/server/data/api',
                  success(res){
                      vm.message = res;
                  }
              });
          }
        })
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
      3. Model层
        {
          "url": "/your/server/data/api",
          "res": {
              "success": true,
              "name": "IoveC",
              "domain": "www.cnblogs.com"
          }
         }
        
        1
        2
        3
        4
        5
        6
        7
        8

# 谈谈Vue和React组件话的思想

  • 我们在各个页面开发的时候,会产生很多重复的功能,比如element中的xxx,像这种纯粹非页面的UI,便成为我们常用的UI组件,最初的前端组件也就仅仅指的是UI组件
  • 随着业务逻辑变的越来越多,我们就想要我们的组件可以处理很多事情,这就是我们常说的组件化,这个组件就不是UI组件,而是包含具体业务的业务组件
  • 这种开发思想就是分而治之.最大程度的降低开发难度和维护成本的效果.并且可以多人协作,每个人写不同的组件,最后像搭积木一样把它构成一个页面

# Vue Complier 实现

  • 模版解析这种事,本质是将数据转化为一段html,最开始出现在后端,经过各种处理吐给前端.随着各种MV*的兴起,模版解析交由前端处理.
  • 总的来说,Vue Complier 是将template转换成一个render 字符串.

可以简单理解为以下步骤

  • parse过程,将templat利用正则转换成AST语法树.
  • optimise过程,标记静态节点,后diff过程跳过静态节点,提升性能.
  • generate过程,生成render字符串.

# Vue3 Watch、watchEffect区别

  • watch是惰性执行,也就是只有监听的值发生变化的时候才会执行,但是watchEffect不同,每次代码加载watchEffect都会执行(忽略watch第三个参数的配置,如果修改配置项也可以实现立即执行)
  • watch需要船体监听的对象,watchEffect不需要
  • watch智能监听响应式数据:ref定义的属性和reactive定义的对象,如果直接监听reactive定义对象中的属性是不允许的(会报警告),除非使用函数转换一下.其实官网上说的监听一个getter
  • watchEffect如果监听reactive定义的对象时不起作用的,只能监听对象中的属性.

看一下watchEffect的代码

```js

```

总结:

  • 如果定义了reactive的数据,想去使用watch监听数据改变,则无法正确获取旧值,并且deep属性配置无效,自动强制开启了深层监听.
  • 如果使用ref初始化一个对象或者数组类型的数据,会被自动转成reacitve的实现方式,生成proxy代理对象.也会变得无法正确取旧值.
  • 用任何方式生成的数据,如果接受的变量时一个pxory代理对象,就会导致watch回调无法正确获取旧值.
  • 所以当大家使用watch监听对象时,如果在不需要使用旧值的情况,可以正常监听对象没关系;但是如果当监听改变函数里面需要用到的旧值时,只能监听对象.xx属性的方式才行 异同总结;
最后更新时间: 2023/1/12 15:59:09