「offer来了」Vue.js篇,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系(下)

简介: 在下面的这篇文章中,将从 vue2 的基础知识,到 vue2 的原理知识,再到 vue3 的基础知识和原理知识做一个归纳和总结。同时,周一也将整理出相关的面试题,以供大家可以有一个更好的参考。下面开始进入本文的讲解~

3、vue如何监听数组变化


要想让 Object.defineProperty() 这个 API 拥有监听数组的能力,我们可以这么做。具体代码如下:

// 触发更新视图
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: 'monday',
    age: 20,
    info: {
        address: '深圳' // 需要深度监听
    },
    nums: ['打篮球', '出来玩', '打乒乓球']
}
// 监听数据
observer(data)
// 测试
data.info.address = '上海' // 深度监听
data.nums.push('神游') // 监听数组
复制代码
复制代码

此时浏览器的打印效果如下:

12.png

我们可以看到,两个数据对应的视图都更新了。通过对数组原型的重新定义,我们就让 Object.defineProperty() 实现了监听数组的能力。


4、请描述响应式原理

11.png响应式原理概述:

  • 任何一个 Vue 组件都会生成一个 render 函数。
  • 之后 render 函数会生成一个 vnode
  • 同时,在执行 render 函数的时候会触发 data 里面的 getter ,触发后则会生成依赖。
  • 所谓依赖,就是在 data 触发到哪个变量,就会将哪一个变量观察起来。
  • 之后,需要查看触发到的这个变量是否是之前作为依赖被观察起来的,如果是,则触发 setter 进行数据修改;如果不是,则直接进行监听操作;
  • 最后,如果确定是之前作为依赖被重新观察起来的,那就执行 re-render 重新渲染操作,并且进行 patch(vnode, newVnode)


5、请用vnode描述一个DOM结构

根据下方的 html 代码,用 v-node 模拟出该 html 代码的 DOM 结构。

html代码:

<div id="div1" class="container">
    <p>
        vdom
    </p>
    <ul style="font-size:20px;">
        <li>a</li>
    </ul>
</div>
复制代码
复制代码

用JS模拟出以上代码的DOM结构:

{
  tag: 'div',
    props:{
        className: 'container',
        id: 'div1'
    },
    children: [
        {
            tag: 'p',
            chindren: 'vdom'
        },
        {
            tag: 'ul',
            props:{ style: 'font-size: 20px' },
            children: [
                {
                    tag: 'li',
                    children: 'a'
                }
                // ....
            ]
        }
    ]
}
复制代码


6、diff算法的时间复杂度

  • 树的时间复杂度是 O(n3) ,因此,我们就想办法,优化其时间复杂度从O(n3)到O(n),以达到操作 vdom 节点,那这个优化过程其实我们所说的 diff 算法。
  • 所以, diff 算法的时间复杂度为 O(n)


7、简述diff算法过程

  • 首先,对比节点本身,要先判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换;
  • 如果为相同节点时,进行 patchVnode ,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的 children 没有子节点,则将旧的子节点移除);
  • 比较如果都有子节点,则进行 updateChildren ,判断如何对这些新老节点的子节点进行操作( diff 核心)。
  • 匹配时,找到相同的子节点,递归比较子节点。

注意:diff 中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从 O(n^3) 降低值 O(n) ,也就是说,只有当新旧 children 都为多个子节点时才需要用核心的 diff 算法进行同层级比较。


8、vue模板编译的原理是什么

  • vue 在进行模板编译之后,会先转化成一个 render 函数,之后继续执行 render 函数,执行完成之后返回一个 vnode
  • 在得到 vnode 之后,基于 vnode 的基础上,再执行 patchdiff


9、vue为何是异步渲染,$nextTick有何用?

  • vue 是组件级更新,一旦当前组件里的数据变了,那么它就会去更新这个组件。
  • 但是试想一下,如果当数据更改一次,组件就要去重新渲染一次,这样对性能来说都是不太友好的。
  • 因此,为了防止数据一更新就更新组件,所以需要异步渲染来处理。
  • 而异步渲染的核心的方法就是 nextTick$nextTick 可以在 DOM 更新完之后,再触发回调


10、SPA单页面应用是什么?

SPA,即单页面应用(Single Page Application)。所谓单页 Web 应用,就是只有一张 Web 页面的应用。单页应用程序 (SPA) 是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的 Web 应用程序。浏览器一开始会加载必需的 HTMLCSSJavaScript ,所有的操作都在这张页面上完成,都由 JavaScript 来控制。

现如今,为了配合单页面 Web 应用快速发展的节奏,各类前端组件化技术栈层出不穷。近几年来,通过不断的版本迭代, vuereact 两大技术栈脱颖而出,成为当下最受欢迎的两大技术栈。


11、hash和history的区别是什么?


(1)hash

  • hash变化会触发网页跳转,即浏览器的前进和后退。
  • hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url
  • hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。
  • hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。


(2)history

  • 新的 url 可以是与当前 url 同源的任意 url ,也可以是与当前 url 一样的地址,但是这样会导致的一个问题是,会把重复的这一次操作记录到栈当中。
  • 通过 history.state ,添加任意类型的数据到记录中。
  • 可以额外设置 title 属性,以便后续使用。
  • 通过 pushStatereplaceState 来实现无刷新跳转的功能。
  • 使用 history 模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果 nginx 没有匹配得到当前的 url ,就会出现 404 的页面。
  • 而对于 hash 模式来说,  它虽然看着是改变了 url ,但不会被包括在 http 请求中。所以,它算是被用来指导浏览器的动作,并不影响服务器端。因此,改变 hash 并没有真正地改变 url ,所以页面路径还是之前的路径, nginx 也就不会拦截。
  • 因此,在使用 history 模式时,需要通过服务端来允许地址可访问,如果没有设置,就很容易导致出现 404 的局面。


12、hash和history两者的选择

  • to B 的系统推荐用 hash ,相对简单且容易使用,且因为 hashurl 规范不敏感;
  • to C 的系统,可以考虑选择 H5 history ,但是需要服务端支持
  • 能先用简单的,就别用复杂的,要考虑成本和收益


🖨️五、vue3.x知识预备


关于 vue3 模块,我将把基础知识原理的内容结合在一起进行整理。详细见下图👇

1.png


⌨️六、vue3.x常见面试题


基于以上知识点,我们将其细分为面试中的常考题。详细见下图👇

2.png

接下来对这些题进行一一解答。


1、vue3和vue2有什么优势?

  • vue3vue2 来说,性能上更好代码体积更小,并且有更好的ts支持
  • 同时,更为突出的特点是, vue3更好的代码组织能力,有更好的逻辑抽离能力,并且还有更多各式各样的新功能
  • 其中尤为突出的就是大家平常耳熟能详的 Composition APIOptions API


2、描述vue3生命周期

以下给出 Vue2Vue3 生命周期的对比。

Vue2生命周期(Options API) Vue3生命周期(Composition API) 含义
beforeCreate setup 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用
created setup 页面还没有渲染,但是vue的实例已经初始化结束。
beforeMount onBeforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted onMounted 页面已经渲染完毕。
beforeUpdate onBeforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated onUpdated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
beforeDestory onBeforeUnmount 实例销毁之前调用。在这一步,实例仍然完全可用。
destroy onUnmounted Vue 实例销毁后调用。


3、如何看待Composition API和Options API

对于 Composition APIOptions API 的使用,主要有以下几点建议:

  • 两者不建议共用,不然很容易引起混乱;
  • 对于小型项目、或者业务逻辑比较简单的项目,建议使用 Options API
  • 对于中大型项目、或者逻辑比较复杂的项目,建议使用 Composition API ,相较于 Options API 来说, Composition API 对大型项目更好一些,逻辑的抽离,代码的复用,使得大型项目得以更好的维护。


4、如何理解ref、toRef和toRefs


(1)ref是什么

  • ref 是可以生成 值类型(即基本数据类型) 的响应式数据;
  • ref 可以用于模板reactive
  • ref 通过 .value 来修改值(一定要记得加上 .value );
  • ref 不仅可以用于响应式,还可以用于模板的 DOM 元素。


(2)toRef是什么

  • toRef 可以响应对象 Object ,其针对的是某一个响应式对象( reactive 封装)的属性 prop
  • toRef 和对象 Object 两者保持引用关系,即一个改完另外一个也跟着改。
  • toRef 如果用于普通对象(非响应式对象),产出的结果不具备响应式。如下代码所示:
//普通对象
const state = {
  age: 20,
  name: 'monday'
}
//响应式对象
const state = reactive({
    age: 20,
    name: 'monday'
})
复制代码


(3)toRefs是什么

  • toRef 不一样的是, toRefs 是针对整个对象的所有属性,目标在于将响应式对象( reactive 封装)转换为普通对象。
  • 普通对象里的每一个属性 prop 都对应一个 ref
  • toRefs 和对象 Object 两者保持引用关系,即一个改完另外一个也跟着改。


5、vue3升级了哪些重要的功能?

  • createApp
  • emits(父子组件间的通信)
  • 多事件处理
  • Fragment
  • 移除 .sync
  • 异步组件
  • 移除filter
  • Teleport
  • Suspense


6、Composition API如何实现代码的逻辑复用?

  • composition API 通过把代码的逻辑抽离出来进行封装,并把封装的内容直接引用到生命周期里面,已达到代码的逻辑复用效果。


7、Vue3如何实现响应式?

  • 利用 reactive 注册响应式对象,对函数返回值进行操作。
  • 利用 Proxy 劫持数据的 get , set , deleteProperty , has , own
  • 利用 WeakMap , Map , Set 来实现依赖收集。
  • 缺点: 使用大量 ES6 新增特性,旧版本浏览器兼容性差。


8、Watch和watchEffect的区别是什么?

  • 两者都可以监听 data 属性变化;
  • watch 需要明确监听哪个属性
  • watchEffect 会根据其中的属性,自动监听其变化。


9、setup中如何获取组件实例?

vue2 中, Options API 可以使用 this 来获取组件的实例,但是到现在的 vue3 ,已经被摒弃掉了。在 setup 和其他 Composition API 中没有 this ,但是它提供了一个 getCurrentInstance 来获取当前的实例。


10、vue3为何比vue2快?

  • Proxy响应式
  • PatchFlag
  • hoistStatic
  • cacheHandler
  • SSR优化
  • tree-shaking


11、vite是什么?

  • vite 是一个前端的打包工具,是 vue 作者发起的一个项目;
  • vite 借助 vue 的影响力,发展较快,和 webpack 有着一定的竞争关系;
  • 优势: vite 使得程序在开发环境下无需打包,且启动非常快速。


12、Composition API和React hooks的对比

  • 前者 setup 只会被调用一次,而后者函数会被多次调用。
  • 前者无需 useMemo useCallback (即缓存数据和缓存函数),因为 setup 只调用一次。
  • 前者无需顾虑调用顺序,而后者需要保证 hooks 的顺序一致。
  • 前者 reactive+ref 比后者的 useState ,要难理解。


📸七、结束语


vue2.x 的基础知识,再到 vue2.x 的原理知识,最后到 vue3.x 的新特性和原理知识学习,全文贯穿着 vue 的知识要点及相关知识点所涉及到的一些面试题。

关于本文的介绍到这里就结束啦!希望对大家有帮助~



相关文章
|
4天前
|
前端开发 JavaScript API
基于Vue3+Hooks实现4位随机数和60秒倒计时
本文介绍了如何在Vue3中使用Hooks API来实现生成4位随机数和执行60秒倒计时的功能,并提供了详细的代码示例和运行效果展示。
21 1
基于Vue3+Hooks实现4位随机数和60秒倒计时
|
4天前
|
数据可视化 JavaScript
Vue3项目使用G6可视化组件实现一个树形机构图
在Vue 3项目中使用G6可视化组件库实现树形机构图的构建和展示。
32 1
Vue3项目使用G6可视化组件实现一个树形机构图
|
3天前
|
JavaScript 算法 API
Vue 3有哪些新特性
【8月更文挑战第16天】Vue 3有哪些新特性
20 1
|
4天前
|
JavaScript UED
如何在Vue3项目中使用防抖节流技巧
在Vue 3项目中使用防抖和节流技巧以优化组件性能,包括使用`lodash`库和自定义实现这两种方法。
8 0
如何在Vue3项目中使用防抖节流技巧
|
4天前
|
JavaScript
创建 Vue3 项目
创建 Vue3 项目
10 0
|
4天前
|
JavaScript
在Vue3+ElementPlus项目中使用具有懒加载的el-tree树形控件
在Vue 3和Element Plus项目中实现具有懒加载功能的el-tree树形控件,以优化大数据量时的页面性能。
6 0
|
4天前
|
JavaScript 前端开发
在Vue3+ElementPlus项目中实现一个简单的新增/移除行记录的小组件
在Vue 3和Element Plus项目中创建一个支持新增和移除行记录的简单表格组件。
25 0
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
59 2
|
16天前
|
JavaScript 前端开发
JS:一篇文章带你搞懂什么是异步
JS:一篇文章带你搞懂什么是异步
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
54 4