最近总结的一波面试题

125 阅读41分钟

VUE

VUE的基本原理

一个vue实例创建时,会遍历data中的属性,用Object.defineProperty(vue3.0中使用proxy)将它们转化为getter/setter,并在内部追踪相关依赖,在属性被访问和修改时通知变化

每个组件都有相应的watcher实例,它会在组件渲染过程中将属性记录为依赖,当依赖项的setter被调用时通知watcher重新计算,致使关联的组件更新

VUE的优点

轻量级框架

上手快,学习成本低

双向数据绑定,保留了angular的特点,数据操作更简单

组件化,保留了react的特点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势

视图、数据、结构分离,使数据更改更简单

虚拟DOM,操作DOM是非常消耗性能的,不再使用原生的DOM操作节点,极大解放了DOM操作

相较于react运行速度更快

双向数据绑定原理:

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

单向数据流和双向数据流的理解

  • v-bind和vuex就是单向数据流

    如一个父组件有两个子组件,分别为a和b ,父组件向子组件传递数据,两个组件都接收到了父组件传递过来的数据,在组件a中修改父组件传递过来的数据,子组件b和父组件的值不会发生变化 这就是单向的数据流

  • v-model就是双向数据流

    Model数据变化会触发View的刷新, View层用户改变数据也会在Model中同步

defineProperty()的使用方法

defineProperty()有三个参数

  • 1.将要被修改的对象

  • 2.将要被修改的对象的属性

  • 3.将要被修改的属性的描述符,就是一个对象,里面有两个属性get和set

    var book = {
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, "year", {
        get: function () {
            return this._year;
        },
        set: function (newValue) {
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004;
            }
        }
    });
    book.year = 2005;
    alert(book.edition);  //2
    

v-model实现原理

v-model实际上是一个语法糖

v-bind绑定value指向message变量

v-on绑定input事件

触发input事件时通过$event.target.value将值赋给message

<input v-model="sth" />
//  等同于
<input 
    v-bind:value="message" 
    v-on:input="message=$event.target.value"
>

使用Object.defineProperty()缺点:

无法检测到对象属性的新增或删除 无法监听数组变化, Vue 内部通过重写函数的方式解决了这个问题

vue2.0如何监听数组的变化:

数组
  1. this.$set(array, index, data)

    //这是个深度的修改,某些情况下可能导致你不希望的结果,因此最好还是慎用
    this.dataArr = this.originArr
    this.$set(this.dataArr, 0, {data: '修改第一个元素'})
    console.log(this.dataArr)        
    console.log(this.originArr)  //同样的 源数组也会被修改 在某些情况下会导致你不希望的结果 
    复制代码
    
  2. splice

    //因为splice会被监听有响应式,而splice又可以做到增删改。
    复制代码
    
  3. 利用临时变量进行中转

    let tempArr = [...this.targetArr]
    tempArr[0] = {data: 'test'}
    this.targetArr = tempA
    
对象
  1. this.$set(obj, key ,value) - 可实现增、改

  2. watch时添加deep:true深度监听,只能监听到属性值的变化,新增、删除属性无法监听

    this.$watch('blog', this.getCatalog, {
        deep: true
        // immediate: true // 是否第一次触发
      });
    
    
  3. watch时直接监听某个key

    watch: {
      'obj.name'(curVal, oldVal) {
        // TODO
      }
    }
    
    

Vue3.0如何解决Object.defineProperty()缺点:

Vue3.0中使用Proxy(对象代理)可以完美的监听到任何数据的变化 缺点:兼容性问题

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

javascript的对象是引用类型,多个组件引用同一个data对象时,当其中一个组件修改对象的数据时其他组件的数据也会发生变化

写成函数的形式当组件复用时,就会返回一个新的data,每个组件都有私有数据空间,不会影响其他组件

常见的事件修饰符

.stop 防止冒泡

<div @click="div">
    <button @click.stop="button"></button>    
</div>
// 当点击button时,先执行button的点击事件,再执行div的点击事件,加上.stop后,就只会执行button的

.prevent 防止执行预设行为

<a href="http://www.baidu.com" @click.prevent="a">百度</a>
// 加上.prevent后,就会阻止默认的跳转行为

.captrue 与事件冒泡的方向相反,事件捕获由外到内

<div @click.capture="div">
    <button @click="button"></button>    
</div>
// 先触发div事件,再触发button事件

.self 只会触发自身事件,不包含子元素

.once 只触发一次

MVVM、MVC、MVP的区别:

MVC,MVP,MVVM是三种常见的软件架构设计模式, 主要通过分离关注点的方式来组织代码结构

  • MVVM

    MVVM分为View、Model、VIewModel

    View代表UI视图,负责数据显示

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

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

    Model和View是没有直接联系的 它们是通过ViewModel进行联系的

    Model和ViewModel有着双向数据绑定的关系

    Model数据变化会触发View的刷新 View层用户改变数据也会在Model中同步

  • MVC

    MVC分为Model、View、Controller

    View负责页面的显示逻辑

    Model负责存储页面的业务数据,以及对数据的操作

    Controller层是View和Model的纽带,主要负责用户与应用的响应操作

    view发布指令给controller,controller选择model,model驱动view

  • MVP

    MVP与MVC唯一的不同点在于Presenter和Controller

    MVP通过使用Presenter来实现View层和Model层的解耦,View层的接口暴露给了Presenter,可以实现View和Model的同步更新

    MVC中的Controller只知道Model的接口,没有办法控制View层更新

对于axios的理解:

axios是一种基于Promise封装的HTTP客户端,是对ajax的进一步封装

特点:

浏览器端发起XMLHttpRequest请求

node端发起http请求

支持Promise API

可以拦截请求和响应

自动转换成JSON数据

token过期时,在响应拦截器中 的 两种处理方法

方法一:用户有感知,重新登录
在响应拦截器中:当用户token过期,请求响应出现401状态码,在响应之前清除token,强制用户跳转到登录页面,尽行重新登录
方法二:用户无感知,直接获取新的token进行请求

在响应拦截器中:当用户token过期,请求响应出现401状态码,清除token,调用获取新token的接口,将新的token存到本地,然后把新获取的token添加到 error.config.headers ,最后重新发起请求并返回

axios || ajax请求一般放在哪个钩子函数中

一般放在created钩子函数中,因为此时data已经初始化,可以缓存获取到的数据,并且请求比较快,用户体验好

mounted中也可以发送请求,但是由于mounted是在模板渲染成html页面后调用,请求比较慢,如果数据比较庞大,这时候可能会导致页面闪屏

请求拦截器和响应拦截器

请求拦截器可以用来配置公共的请求头,加载弹窗等,示例代码中弹窗使用的mint-UI,也可以使用其他UI框架,注意使用前安装、引入; 请求拦截器 在请求发送前进行一系列操作,例如在每个请求体上加上token,统一做处理,以后要改也容易

响应拦截器可以用来针对后端返回的类型做统一的处理,比如给一些提示;请求拦截里如果加了加载框,这里也可以统一关闭;

响应拦截器 接收响应后进行一系列操作,例如服务器返回登陆状态失效,需要重新登陆,跳转到登录页

ajax、fetch的区别

  • ajax

    ajax是一种创建交互式网页应用的网页开发技术

    是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术

    本质是使用XMLHttpRequest对象来请求数据

    它是jquery库里自带的一个方法

  • fetch

    fetch是原生js,没有使用XMLHttpRequest对象

    基于标准Peomise实现,支持async/await

v-if和v-show的区别:

v-if是动态的向DOM树内添加或删除元素

v-show是通过设置DOM元素的display来控制元素的显示隐藏

v-if有更高的切换消耗

v-show有更高的初始渲染消耗

v-if适合运营条件不大改变

v-show适合频繁的切换

一般权限按钮上会用到v-if

v-for 与 v-if 的优先级

当它们处于同一节点, v-for的优先级比v-if更高 ,这意味着 v-if将分别重复运行于每个 v-for循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,如下:

上面的代码只传递了未完成的 todos。

而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或