在Vue2中: 组件必须有一个根标签
在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
好处: 减少标签层级, 减小内存占用
v-model的作用是更新数据,视图发生变化,我们可以用v-bind把value绑定到msg上,当用户更新数据的时候,我们可以监听input事件,input事件和chang事件有什么区别呢?input事件当用户输入的时候就会触发,chang事件是当用户输入完成之后触发,然后用window.addeventlistener监听用户输入事件,然后把用户输入的内容绑定到msg上,这样的话,v-model整个就实现了
通过Object.defineProperty()给value的属性添加getter、setter来实现响应式,一般用来处理基本数据类型,也能处理复杂数据类型,只不过内部会自动将对象转换为reactive的代理对象,在js中要加.value,在模版中不需要
通过Proxy对目标对象中的所有属性动态地进行数据劫持,并通过Reflect操作对象内部数据来实现响应式,一般用来处理复杂数据类型,会实现递归深度响应式
这两个函数都能监听数据的变化,但从实用角度上讲,他们十分类似,都能通过监听数据变化来触发回调函数
watchEffect会自动追踪函数内部使用的数据变化,当数据变化时,触发回调函数,所以watchEffect更智能
watch是需要指定被监听的数据,当被指定的数据发生变化时,触发回调函数
watchEffect的函数会立即执行一次,并在数据发生变化的时候再次执行
watch的回调函数只有在侦听的数据发生变化的时候才会执行,默认不会立即执行
watch可以更精细的控制监听行为,比如设置deep,immediate,flush
watchEffect更适合简单的场景,不需要额外的配置,相当于默认开启了deep和immediate
都是观察数据变化的(相同)
计算属性将会混入到 vue 的实例中,所以需要监听自定义变量;watch 监听 data 、props 里面数据的变化;
computed 有缓存,它依赖的值变了才会重新计算,watch 没有;
watch 支持异步,computed 不支持;
watch 是一对多(监听某一个值变化,执行对应操作);computed 是多对一(监听属性依赖于其他属性)
watch 监听函数接收两个参数,第一个是最新值,第二个是输入之前的值;
computed 属性是函数时,都有 get 和 set 方法,默认走 get 方法,get 必须有返回值(return)
- :在侦听器创建时立即触发回调。第一次调用时旧值是 。
- :如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。
- :调整回调函数的刷新时机。参考回调的刷新时机及 。
- :调试侦听器的依赖。参考调试侦听器。
- :回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。
conputed本质是一个惰性的观察者;当计算数据存在于 data 或者 props里时会被警告;
vue 初次运行会对 computed 属性做初始化处理(initComputed),初始化的时候会对每一个 computed 属性用
watcher 包装起来 ,这里面会生成一个 dirty 属性值为 true;然后执行 defineComputed 函数来计算,计算之后会将 dirty 值变为 false,这里会根据 dirty 值来判断是否需要重新计算;如果属性依赖的数据发生变化,computed 的 watcher 会把 dirty 变为 true,这样就会重新计算 computed 属性的值。
nextTick方法将回调延迟到下次DOM更新循环之后执行。Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。
nextTick 的核心是运用了 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微任务和宏任务,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列
原型链的本质是一个链表,当你new一个构造函数的时候,它会返回一个实例,当你在实例上面没找到,它会顺着它的proto属性指向它的原型,去它的原型上去找,如果原型上没找到,它会顺着它的原型的原型去找,一直找到大Object的原型,原型链的终点是 null,因为Object是构造函数,所以原型链终点是Object.prototype.proto,也就是null
它的应用场景是比如jquery源码,它所有的源码都放在了$原型上,以便于我们每个文件都能使用,以及vue2本身不支持数组的双向绑定,所以vue的作者改变了源码,通过原型链的继承属性,来让push支持双向绑定
原生JS执行是单线程的,基于事件循环。事件循环大致分为以下步骤:
1.所有同步任务都在主线程上执行,形成一个执行栈。
2.异步任务放进任务队列,异步任务分为宏任务和微任务
3.执行栈所有同步任务执行完成,就会执行任务队列。对应的异步任务,结束等待状态,进入执行栈,开始执行。
4.主线程不断重复上面的第三步。
主线程的执行过程就是一个 tick,而所有的异步结果都是通过 “任务队列” 来调度。 消息队列中存放的是一个个的任务(task)。 task 分为两大类,分别是 macro task 和 micro task,并且每个 macro task(宏任务) 结束后,都要清空所有的 micro task(微任务)。
JS事件循环,Event Loop
1.同步任务和异步任务分别进入不同的执行场所,同步任务进入主线程,异步任务进入Event Table并且注册回调函数
2.当执行的事情完成之后,EventTable会将这个函数植入任务队列,等待主线程的任务执行完毕
3.当栈中的代码执行完毕,执行栈中的任务为空时,就会读取任务的回调
4.如此循环,就形成了事件循环的机制
JS事件表格,Event Table
1.Event Table 可以理解为一张事件和回调函数的对应表
2.Event Table 用来存储JS中的异步事件以及对应的回调函数列表用的
3.当执行的事件完成时,Event Table会将这个回调函数移入宏任务队列或微任务队列
具体来说,当一个宏任务执行完毕后,会立即检查微任务队列中是否有待执行的微任务。如果有,则按照先进先出的顺序依次执行所有的微任务,直到微任务队列为空。然后才会执行下一个宏任务。
执行顺序是:
执行同步代码,输出 ;
遇到setTimeout,将其回调函数放入宏任务队列;
遇到Promise,将其回调函数放入微任务队列;
输出 ;
当前宏任务执行完毕,执行微任务队列中的所有微任务,输出 ;
执行浏览器UI线程的渲染工作;
检查是否有Web Worker任务,如果有则执行;
执行下一个宏任务,取出setTimeout的回调函数,输出 。
vue3的setup语法糖没有beforeCreate和created,直接用setup代替
onBeforeMont:创建前 => 在onBeforeMont读不到dom,因为这个时候,dom还没有被渲染
onMounted:创建后 => 在onMounted可以读到dom,因为这个时候,dom已经被渲染
onBeforeUpdate:更新前 => 在更新组件中获取dom,onBeforeUpdate获取到的同样也是更新之前的dom
onUpdated:更新后 => 在更新组件中获取dom,onUpdated获取到的才是更新之后的dom
onBeforeUnmount:销毁前
onUnmounted:销毁后
还有用于调试的两个生命周期函数:
onRenderTracked:默认先执行
onRenderTriggered:当触发更新生命周期函数的时候执行并返回更新之后的数据
父组件:beforeCreate -> created -> beforeMount
子组件:beforeCreate -> created -> beforeMount -> mounted
父组件:mounted
更新过程中:
父组件:beforeUpdate
子组件:beforeUpdate -> updated
父组件:updated
销毁过程中:
父组件/子组件:beforeDestroy
父组件/子组件:destroyed
在依赖和收集中有三个非常核心的类,分别是Observer,watcher,dep,当组件实例化的时候,Observer也会进行实例化,它将会对data中的属性进行遍历,用defineProperty对每一个属性进行劫持,然后针对每一个属性会生成一个该属性对应的dep,并且在get中调用dep.depend方法,将dep实例和watch实例,并且用一个数组subs进行关联,在set里调用dep.notify,notify将对subs进行遍历,执行watcher中绑定的render来更新组件
Proxy是ES6新增的方法,主要用于创建一个对象的代理,从而实现基本操作的拦截和定义
- Object.defineProperty只能遍历对象属性进行劫持
- Proxy直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的
- Proxy可以直接监听数组的变化(push、shift、splice)
- Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的
虚拟dom是通过JS生成的一个AST节点树,AST是抽象语法树,之所以使用AST抽象语法树,是因为很多地方都会用到,比如TS转JS,babel插件(ES6转ES5),或者JS通过V8引擎帮我们转字节码的时候,都会用到,当然在Vue中,也是帮我们将dom转换为虚拟dom,为什么不直接操作dom?因为一个dom的属性是非常多的,如果直接操作dom,会十分浪费性能。操作虚拟dom的好处还可以做很多算法的优化,比如比较常见的diff算法
dom会生成两个vnode,一个是新的vnode,一个是旧的vnode,第一步是通过for循环去patch,重新渲染元素,第二步是删除旧的vnode,第三步是新增新的vnode。diff算法会做替换,虚拟dom会做新旧对比,新的会把旧的替换掉,如果发现多了的,就新增并插入,如果发现少了就删除。
同样也会进行新旧对比,有key的diff算法一共分为五步: 前置算法,只对比前面的,while循环,通过isSameVNodeType方法进行判断type和key比较是否一样,如果一样,返回true,则复用,其中type就是div,key就是我们绑定的key值,当发现不一样的时候,就会break跳出循环,进行尾序算法对比,前两种算法的作用是头和头,尾和尾进行对比
vue3和vue2的双端diff算法,不同的是,vue2也是头和头,尾和尾,头和尾,尾和头,这是和vue3的区别,vue3进行了diff算法优化,vue3还做了最长递增子序列算法,当头尾比对完之后,发现多了,就会走第三步,第三步是新增,首先还是while循环,通过patch,如果参数为null,就会走新增,如果发现少了,就会通过unmount执行卸载
1.构建新节点的映射关系:key值对应 0 1 2 3 4 索引,构建map关系
2.记录新节点在旧节点中的位置数组:如果有多余的旧节点,则删除掉,如果新节点不包含旧节点,也给删掉,如果节点出现交叉,说明是移动,并且要去求最长递增子序列,并且moved赋值为true
3.求最长递增子序列升序算法:写了一个getSequence函数方法,实现了贪心算法+二分查找实现最长递增子序列算法,求出来之后判断,如果当前遍历的这个节点不在子序列中,说明要求移动,否则如果在子序列中,那么就直接跳过
给该元素增加style为display:none,但是dom元素还在,当条件切换的时候,只是做css的display:none和block的切换
v-show切换的时候,不会出触发组件的生命周期
true或者false,是将dom元素整个添加或者删除
切换过程中会执行组件的编译和卸载过程,并且销毁和重建内部事件监听和子组件
v-if由false切换为true的时候,会触发组件的beforeCrate,create,beforeMount,mounted
v-if由true切换为false的时候,会触发组件的beforeDestory和distoryed
所以v-if做切换的时候会增加性能的消耗
是通过原型链实现的。作用是在根组件注册一次,在其他的子组件都可以访问到数据
路径会带#,因为是location.hash去匹配的,当我们在控制台输入的时候,会返回一个#/
监听路由变化的原理是通过window.addEventListener的event回调函数去监听左右浏览器回退或前进箭头的变化,event回调函数去返回newUrl和oldUrl,从而实现跳转
路径不带#,因为history是基于h5的history方法实现的
监听路由变化的原理是通过window.addEventListener,有一个popState回调函数,通过event回调函数去监听,event会返回一个state对象,返回的对象里包含back(上一个url地址)和current(当前url地址)
跳转原理是通过history.pushState结合vue内置跳转方法实现跳转的
vue2:哈希:hash
vue3:哈希:createWebHash
vue2:history:history
vue3:history:createWebHistory
在Vue中,key 是一个特殊的属性,它主要用于给通过 v-for 指令渲染的列表中的每个元素或组件分配一个唯一的标识符
这个属性在Vue的虚拟DOM渲染和更新过程中起着至关重要的作用
唯一性:key 的值必须是唯一且稳定的,它用于识别每个节点的身份。当使用 v-for 迭代列表时,Vue 使用 key 来跟踪每个节点的身份和状态。 稳定性:使用稳定的 key 值可以帮助 Vue 更准确地判断节点的变化情况,从而减少不必要的DOM操作。
高效更新:Vue 在进行虚拟DOM的diff算法比较新旧节点时,如果节点具有相同的 key,Vue 会认为它们是相同的节点,从而避免不必要的重新渲染,提高渲染效率。 复用元素:当列表数据变化时(如添加、删除、重新排序),Vue 会尽量复用现有的DOM元素,而不是重新创建它们。使用 key 可以帮助 Vue 更准确地识别哪些元素是可以复用的,哪些是需要更新的。
状态保留:在使用 v-for 渲染列表项时,如果列表项包含状态(如输入框的值、复选框的选中状态等),并且列表项的顺序会发生变化,使用 key 可以确保在重新渲染时,Vue 能够正确地保留每个列表项的状态。
错误复用:如果不使用 key 或 key 值不唯一,Vue 在更新列表时可能会错误地复用DOM元素,导致显示错误的数据或状态
要确保key的唯一性:在大多数情况下,可以使用数据的唯一标识符(如id)作为 key
添加key可以增加稳定性:key 的值应该是稳定的,不应频繁变化。避免使用index索引作为 key,特别是在列表会进行动态排序或过滤的情况下
到此这篇vue2.(vue2和vue3区别面试题)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdvuejs/19885.html