前端框架面试之 Vue 面试真题 和 Vue3 相关考点

一、Vue 面试真题
  1. v-showv-if 的区别,答案如下所示:
  • v-show 通过 CSS display 控制显示与隐藏
  • v-if 组件真正的渲染和销毁,而不是显示与隐藏
  • 频繁切换显示状态用 v-show,否则用 v-if
  1. 为何在 v-for 中用 key,答案如下所示:
  • 必须用 key,且不能是 indexrandom
  • diff 算法中通过 tagkey 来判断,是否是 sameNode
  • 减少渲染次数,提升渲染性能
  1. Vue 组件如何通讯,常见的方式,答案如下所示:
  • 父子组件 propsthis.$emit
  • 自定义事件 event.$on、event.$off 和 event.$emit
  • vuex
  1. 双向数据绑定 v-model 的实现原理,答案如下所示:
  • input 元素的value = this.name
  • 绑定 input 事件 this.name = $event.target.value
  • data 更新触发 re-render
  1. computed 有何特点,答案如如下所示:
  • 缓存,data 不变不会重新计算
  • 提高性能
  1. ajax 请求应该放在哪个生命周期,答案如下所示:
  • mounted 生命周期函数
  • JS 是单线程的, ajax是异步获取数据
  • 放在 mounted 之前没有用,只会让逻辑更加混乱
  1. 如何将组件所有 props 传递给子组件,答案如下所示:
  • $props
  • <User v-bind = "$props" />
  • 细节知识点,优先级不高
  1. 多个组件有相同的逻辑,如何抽离,答案如下所示:
  • 使用 mixin
  1. 何时要使用异步组件,答案如下所示:
  • 加载大组件
  • 路由异步加载
  1. 何时需要使用 keep-alive,答案如下所示:
  • 缓存组件,不需要重复渲染
  • 如多个静态 tab 页的切换
  • 优化性能
  1. 何时需要使用 beforeDestory,答案如下所示:
  • 解绑自定义事件 event.$off
  • 清除定时器
  • 解绑自定义的 DOM 事件,如 window scroll
  1. Vuexactionmutation 有何区别,答案如下所示:
  • action 中处理异步,mutation 不可以
  • mutation 做原子操作
  • action 可以整合多个 mutation
  1. Vue-router 常用的路由模式,答案如下所示:
  • hash 默认
  • H5 history,需要服务端支持
  • 两者比较
  1. 监听 data 变化的核心 API 是什么,答案如下所示:
  • Object.defineProperty
  • 深度监听、监听数组
  • 有何缺点
  1. Vue 如何监听数组变化,答案如下所示:
  • Object.defineProperty 不能监听数组变化
  • 重新定义原型,重写 pushpop 等方法,实现监听
  • Proxy 可以原生支持监听数组变化
  1. 请描述响应式原理,答案如下所示:
  • 监听 data 变化
  • 组件渲染和更新的流程
  1. diff 算法的时间复杂度,答案如下所示:
  • O(n)
  • O(n^3) 基础上做了一些调整
  1. 简述 diff 算法过程,答案如下所示:
  • patch(elem, vnode)patch(vnode, newVnode)
  • patchVnodeaddVnodesremoveVnodes
  • updateChildrenkey 很重要
  1. Vue 为何是异步渲染,$nextTick 何用,答案如下所示:
  • 异步渲染以及合并 data 修改,以提高渲染性能
  • $nextTickDOM 更新完成之后,触发回调
  1. Vue 常见的性能优化方式,答案如下所示:
  • 合理使用 v-showv-if
  • 合理使用 computed
  • v-for 时加 key,以及避免和 v-if 同时使用
  • 自定义事件、DOM 事件以及销毁
  • 合理使用异步组件
  • 合理使用 keep-alive
  • data 层级不要太深
  • 使用 vue-loader 在开发环境做模版编译,预编译
  • webpack 层面的优化
  • 前端通用的性能优化,如图片懒加载
  • 使用 SSR
二、Vue3 的相关考点
  1. Vue3 虽然尚未发布,还在开发中,但是还是很重要的,在面试中也还是会考察的。Vue3 中升级的内容,如下所示:
  • 全部用 ts 重写,响应式、vdom、模版编译等
  • 性能提升,代码量减少
  • 会调整部分 API
  1. Vue2.x 马上就要过时了吗,答案如下所示:
  • Vue3 从正式发布到推广开来,还需要一段时间
  • Vue2.x 应用范围非常广,有大量项目需要维护、升级
  • Proxy 存在浏览器兼容性问题,且不能 polyfill
  • Vue3 比较重要的一点,就是重写响应式
  1. Object.defineProperty 的缺点,如下所示:
  • 深度监听需要一次性递归
  • 无法监听新增属性和删除属性,Vue.setVue.delete
  • 无法原生监听数组,需要特殊处理
  1. Proxy 实现响应式,基本使用、Reflect 和 实现响应式。对于 Reflect 的作用,和 Proxy 能力一一对应,规范化、标准化、函数式,替代掉 Object 上的工具函数。

  2. Proxy 实现响应式,深度监听,性能更好,可监听新增和删除属性,可监听数组变化。Proxy 能够规避 Object.defineProperty 的问题,Proxy 无法兼容所有浏览器,无法 polyfill

  3. 关于响应式的相关代码,如下所示:

  • observe.js
// 触发更新视图
function updateView() {
    console.log('视图更新')
}

// 重新定义数组原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    arrProto[methodName] = function () {
        updateView() // 触发视图更新
        oldArrayProperty[methodName].call(this, ...arguments)
        // Array.prototype.push.call(this, ...arguments)
    }
})

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    // 深度监听
    observer(value)

    // 核心 API
    Object.defineProperty(target, key, {
        get() {
            return value
        },
        set(newValue) {
            if (newValue !== value) {
                // 深度监听
                observer(newValue)

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue

                // 触发更新视图
                updateView()
            }
        }
    })
}

// 监听对象属性
function observer(target) {
    if (typeof target !== 'object' || target === null) {
        // 不是对象或数组
        return target
    }

    // 污染全局的 Array 原型
    // Array.prototype.push = function () {
    //     updateView()
    //     ...
    // }

    if (Array.isArray(target)) {
        target.__proto__ = arrProto
    }

    // 重新定义各个属性(for in 也可以遍历数组)
    for (let key in target) {
        defineReactive(target, key, target[key])
    }
}

// 准备数据
const data = {
    name: 'zhangsan',
    age: 20,
    info: {
        address: '北京' // 需要深度监听
    },
    nums: [10, 20, 30]
}

// 监听数据
observer(data)

// 测试
// data.name = 'lisi'
// data.age = 21
// // console.log('age', data.age)
// data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
// delete data.name // 删除属性,监听不到 —— 所有已 Vue.delete
// data.info.address = '上海' // 深度监听
data.nums.push(4) // 监听数组

  • proxy.js
// const data = {
//     name: 'zhangsan',
//     age: 20,
// }
const data = ['a', 'b', 'c']

const proxyData = new Proxy(data, {
    get(target, key, receiver) {
        // 只处理本身(非原型的)属性
        const ownKeys = Reflect.ownKeys(target)
        if (ownKeys.includes(key)) {
            console.log('get', key) // 监听
        }

        const result = Reflect.get(target, key, receiver)
        return result // 返回结果
    },
    set(target, key, val, receiver) {
        // 重复的数据,不处理
        if (val === target[key]) {
            return true
        }

        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        // console.log('result', result) // true
        return result // 是否设置成功
    },
    deleteProperty(target, key) {
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        // console.log('result', result) // true
        return result // 是否删除成功
    }
})


  • proxy-observe.js
// 创建响应式
function reactive(target = {}) {
    if (typeof target !== 'object' || target == null) {
        // 不是对象或数组,则返回
        return target
    }

    // 代理配置
    const proxyConf = {
        get(target, key, receiver) {
            // 只处理本身(非原型的)属性
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('get', key) // 监听
            }
    
            const result = Reflect.get(target, key, receiver)
        
            // 深度监听
            // 性能如何提升的?
            return reactive(result)
        },
        set(target, key, val, receiver) {
            // 重复的数据,不处理
            if (val === target[key]) {
                return true
            }
    
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('已有的 key', key)
            } else {
                console.log('新增的 key', key)
            }

            const result = Reflect.set(target, key, val, receiver)
            console.log('set', key, val)
            // console.log('result', result) // true
            return result // 是否设置成功
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key)
            console.log('delete property', key)
            // console.log('result', result) // true
            return result // 是否删除成功
        }
    }

    // 生成代理对象
    const observed = new Proxy(target, proxyConf)
    return observed
}

// 测试数据
const data = {
    name: 'zhangsan',
    age: 20,
    info: {
        city: 'beijing',
        a: {
            b: {
                c: {
                    d: {
                        e: 100
                    }
                }
            }
        }
    }
}

const proxyData = reactive(data)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值