VUE面试题

说一下双向数据绑定的原理?

双向数据绑定原理就是采用数据劫持和发布订阅者模式实现的,通过object.defineProterty去劫持每个属性的getter和setter属性,去做相应的更新回调

       1、要实现一个observer,去遍历数据,给每个属性都加上setter和getter属性,这样数据更新的话,就能监听到数据的变化。

        2、实现一个模板解析器compile,它负责把模板的变化装换成数据,同时监听更新数据的订阅者,收到通知,更新视图。

        3、实现一个订阅者watcher,就是observer和compile的桥梁,它主要做的就是,

                在自身实例化的时候往属性订阅器dep中添加自己

                observer监听到数据变化时,会通过属性订阅器dep告知订阅者watcher,就是dep.notify()

                watcher收到通知后,会执行自身的update方法,触发compile。

这样就实现了双向绑定。


Vue是如何监听数组变化的?

        Vue正常是监听不到对象类型的数据变化的,Vue通过重写Array的常用方法,通过包装之后的数组方法就能够去在调用的时候被监听到。通过原型链去拦截对数组的操作,从而实现对操作数组这个行为的监听。

    Proxy所带来的,是对底层操作的拦截。前面我们在实现对对象监听时使用了Object.defineProperty,这个其实是 JS 提供给我们的高级操作,也就是通过底层封装之后暴露出来的方法。Proxy的强大之处在于,我们可以直接拦截对代理对象的底层操作。这样我们相当于从一个对象的底层操作开始实现对它的监听。

            基础类型,我们还是通过Object.defineProperty来实现响应式的属性,因为这里并不存在痛点,但是在实现对Object类型的属性进行监听的时候,我采用的是创建代理,因为我们之前的痛点在于无法去有效监听数组的变化。


为何Vue采用异步渲染?

        因为不采用异步更新,在每次更新数据都会对当前组件进行重新渲染。所以为了性能考虑,vue 会在本轮数据更新后,再去异步更新视图。

       vue是组件级更新,当前组件里的数据变了,它就会去更新这个组件。当数据更改一次组件就要重新渲染一次,性能不高,为了防止数据一更新就更新组件,所以做了个异步更新渲染。(核心的方法就是nextTick)        


$next的实现原理?

      Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,如果同一个 watcher 被多次触发,只会被推入到队列中一次。去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。

        总的来说就是一个回调,在使用的时候,及时将异步任务队列的回调吐出来,即可执行

        1、nextTick是对setTimeout进行了多种兼容性的处理,nextTick优先放入微任务执行,而setTimeout是宏任务,因此nextTick一般情况下总是先于setTimeout执行。


何时需要使用beforeDestory?

        1、可能在当前页面中使用了 $on 方法,需要在组件销毁前解绑

        2、清除自己定义的定时器

        3、解除事件的绑定 scoll mousemove


Vue的父子组件生命周期调用顺序 ?

        父子组件在加载的时候,执行的先后顺序为父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted


Vue的computed的特点?

        1、支持缓存,只有相关依赖(基于data中声明过 或者 父组件传递的props中的数据, vuex的mapstate)的数据发生变化才会执行,不支持异步

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


watch和computed的差异?

        1、computed是计算一个新的属性,并将该属性挂载到vm(Vue实例)上,而watch是监听已经存在且已挂载到vm上的数据,所以用watch同样可以监听computed计算属性的变化(其它还有data、props)

         2、computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,而watch则是当数据发生变化便会调用执行函数

     


watch的deep: true是如何实现的?

        当前监控的值是数组类型,会对对象中的每一项进行求值,此时会将当前的watcher存入到对应属性的依赖中,这样数组中对象发生变化时,也会通知数据更新。


new Vue内部做了什么?

        1、执行构造函数

        2、绑定vm上下文

        3、如果options._isComponent为true,则会进行初始化操作,如果不是,则会合并配置

        4、初始化事件,初始化生命周期,初始化渲染等

        5、执行beforeCreate生命周期函数

        6、初始化data和props,注入inject

        7、初始化data和props的双向数据绑定

        8、初始化data和props,注入provide

        9、执行created函数

        10、检测el属性,vm.$mount 方法挂载 vm, 然后渲染成最终的dom 在h函数中执行。

        


从A组件跳到B组件,声明周期怎么走的?

        1、B的beforeCreate

        2、B的created

        3、B的beforeMount

        4、A的beforeDestroy

        5、A的destroyed

        6、B的mounted


diff算法的理解?

        通过新旧节点的比对,去更新虚拟dom

        1、如果比对的是根节点,就会通过patch函数去做比对,如果不一样,就直接替换

        2、如果根节点一致,就会去找根节点下的文本,图片,等,这个时候通过的是patchVnode函数去做比对的,如果不一致就删除老的替换新的,如果都一致,就会再去找子节点,前提是newVnode !== oldVnode

        3、子节点的判断就进入了updateChildren函数中,

        总之比对就是不断的patchVnode -> updateChildren -> patchVnode -> updateChildren

循环往复的过程


Vue的虚拟dom和React的虚拟dom有什么区别?

1、Vue的虚拟DOM侧重于实现实时响应数据到视图的变化;而React的虚拟DOM则侧重于建立的易理解的、单向的组件树,实现对组件的操作和数据流处理。

2、Vue的虚拟dom使用独立的渲染函数将虚拟dom渲染成真实dom;而React的虚拟dom则提供React Element(节点单元)用于定义组件的结构,也可以说是映射真实dom的属性和方法。

3、Vue的虚拟DOM主要实现了响应式的模板渲染、模板合并、节点的虚拟复制和虚拟DOM对象的复用等功能;而React的虚拟DOM实现了组件的封装、组件的复用、组件的渲染和更新、虚拟DOM树的合并和种子节点渲染等功能。


虚拟dom在什么时候产生的?

        虚拟dom是在render函数的h函数中产生的,h函数负责将template模板转换成虚拟dom


调用接口一般放在哪个生命周期中,为什么?

        一般在created中,这个时候在加载dom之前,如果放在mounted中,再去加载数据,可能会闪屏。但是不绝对,如果你需要加载数据的时候还要操作dom, 就需要放在mounted中了。


为什么vue3比vue2快? 为什么3打包就小?

        1、options API,代码要放在单独的位置,data定义数据, props接收数据,methods方法等等, 需要的内容在各个位置都有,难以维护。还有就是minxins共享方法和数据的错乱,vue3将需要的函数和数据统一放在了setup中,通过返回使用,

        2、ts编写,支持强类型校验,在编译的时候就校验,缩短了在运行时校验的时间

        3、Suspense和异步组件

        4、由于 JavaScript 的限制,Vue 不能检测出数据的改变,所以当我们需要动态改变数据的时候,Vue.set()完全可以满足我们的需求,现在有了ref之后,就不再需要了

        5、hoistStatic 静态提升

                vue2无论元素是否参与更新,每次都会重新创建然后再渲染

                

<div>
    <div>共创1</div>
    <div>共创2</div>
    <div>{{name}}</div>
</div>

静态提升之前

export function render(...) {
    return (
        _openBlock(),
        _createBlock('div', null, [
            _createVNode('div', null, '共创1'),
            _createVNode('div', null, '共创2'),
            _createVNode(
                'div',
                null,
                _toDisplayString(_ctx.name),
                1 /* TEXT */
            ),
        ])
    )
}

                vue3对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可。

提升之后:



const _hoisted_1 = /*#__PURE__*/ _createVNode(
    'div',
    null,
    '共创1',
    -1 /* HOISTED */
)
const _hoisted_2 = /*#__PURE__*/ _createVNode(
    'div',
    null,
    '共创2',
    -1 /* HOISTED */
)

export function render(...) {
    return (
        _openBlock(),
        _createBlock('div', null, [
            _hoisted_1,
            _hoisted_2,
            _createVNode(
                'div',
                null,
                _toDisplayString(_ctx.name),
                1 /* TEXT */
            ),
        ])
    )
}

从以上代码中我们可以看出,_hoisted_1 和_hoisted_2 两个方法被提升到了渲染函数 render 之外,也就是我们说的静态提升。通过静态提升可以避免每次渲染的时候都要重新创建这些对象,从而大大提高了渲染效率。

        6、diff算法的优化

                vue2中的虚拟dom是全量的对比(每个节点不论写死的还是动态的都会一层一层比较,这就浪费了大部分事件在对比静态节点上)

                vue3新增了静态标记(patchflag)与上次虚拟节点对比时,只对比带有patch flag的节点(动态数据所在的节点);可通过flag信息得知当前节点要对比的具体内容。

        

<div>
 <p>云驻共创</p>
 <p>如何评价 vue3</p>
 <p>{{msg}}</p>
</div>

              

div内包含三个段落,其中前两个段落是静态固定不变的,而第三个段落的内容绑定的msg属性,当msg改变的时候,Vue会生成新的虚拟DOM然后和旧的进行对比。当视图更新时,只对动态节点部分进行diff运算,减少了资源的损耗。Patchflag是个枚举,取值为1代表这个元素的文本是动态绑定的,取值为2代表元素的class是动态绑定的。

 

7、按需编译

        vue3中大多数的API都通过es模块导出来,这就让编译器生成一个友好的按需加载模块。这样的话也会减少它的体积。        


***object.fefineProperty与proxy对比?

       

 

 


vue2,vue3和react的diff算法的区别?

react的diff,仅右移 

vue2的diff  双端比较

 

 vue3的diff叫做最长递增子序列

diff算法具体做了什么(重点)?

循环为何必须使用key? 

vue如何监听组件报错?

window.error 只有这个可以监听到异步的报错

 

 


vue的路由守卫有哪些?

全局:

1. router.beforeEach

2.router.beforeResolve

3.router.afterEach

路由独享:

beforeRouteEnter

beforeRouteUpdate

beforeRouteLeave


vue2的v-model和vue3的v-model实现方式上有什么区别?

  vue2只允许一个v-model,vue3可以有多个v-model

vue2中的.sync
//子组件
this.$emit('update:title', newValue)
//父组件
<ChildComponent :title.sync="pageTitle" />
//等价于
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

vue3
//子组件
this.$emit('update:modelValue', newValue)
<ChildComponent v-model="pageTitle" />
// 等价于
<ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event"/>


vuex和pinia的区别?

 (1)pinia它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据
 (2)pinia他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦一点

 (3)pinia语法上比vuex更容易理解和使用,灵活。
 (4)pinia没有modules配置,没一个独立的仓库都是definStore生成出来的

 (5)pinia state是一个对象返回一个对象和组件的data是一样的语法
 

npm install vuex-persistedstate --save  vuex的持久化存储

pinia **数据持久化使用pinia-plugin-persist **


ref reactive的区别? 

reactive:

(1)它的响应式是更加‘深层次’的,底层本质是将传入的数据包装成一个Proxy。

(2)参数必须是对象或者数组,如果要让对象的某个元素实现响应式时比较麻烦。需要使用toRefs解构

ref:

(1)函数参数可以是基本数据类型,也可以接受对象类型

(2)如果参数是对象类型时,其实底层的本质还是reactive,系统会自动根据我们给ref传入的值转换成:

ref(1)->reactive({value:1})
ref函数只能操作浅层次的数据,把基本数据类型当作自己的属性值;深层次依赖于reactive

(3)在template中访问,系统会自动添加.value;在js中需要手动.value

(4)ref响应式原理是依赖于Object.defineProperty()get()set()的。


ref toRef, toRefs的区别? 
  • ref:复制,修改响应式数据不影响以前的数据;数据改变,界面自动更新

  • toRef:引用,修改响应式数据会影响以前的数据;数据改变,界面不自动更新

  • (1)接收一个对象作为参数,它会遍历对象身上所有属性,然后调用单个toRef

    (2)将对象的多个属性变成响应式数据,并且要求响应式数据和原始数据关联,且更新响应式数据的时候不会更新界面,用于批量设置多个数据为响应式


vue如何做权限管理

Vue可以通过路由守卫、自定义指令/ Mixin等实现权限管理:

1、路由守卫:可以在每次跳转前验证用户权限,根据不同权限决定是否允许跳转。

2、自定义指令/ Mixin :可以在页面渲染时,根据用户角色动态化显示或屏蔽某些部分。

3、自定义权限:可以在系统中自定义不同权限,方便灵活管理不同用户权限。


vue-router MemoryHistory?

MemoryHistory,在切换路由的时候,网页输入框,没有后边的路由参数变化,不允许前进后退,其他两个可以前进后退 


vue使用过程中遇到哪些坑?

        1、内存泄露, 全局变量全局事件全局定时器导致

vue2的问题, vue3没有

        2、data删除属性用Vue.delete, 新增属性用Vue.set

        3、无法直接修改数据arr[index] = value

        4、vue scroll切换页面到顶部, 方案:执行scrollTo,, 或者使用mpa+APP webview


vue3与vue2生命周期比对?
vue2                                     vue3
beforeCreate                         ->   setup()
created                                 ->   setup()
beforeMount                          ->   onBeforeMount
mounted                                ->    onMounted
beforeUpdate                        ->    onBeforeUpdate
updated                                 ->    onUpdated
beforeDestroyed                    ->    onBeforeUnmount
destroyed                              ->     onUnmounted
activated                                ->     onActivated
deactivated                            ->     onDeactivated

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值