vue基础面试题

1.Vue指令

v-bind:动态绑定数据
v-on:绑定事件监听器
v-for:循环指令,可以循环数组或对象
v-if:根据表达式的真假值,判断是否渲染元素,会销毁并重建
v-show:显示隐藏元素,修改元素的display属性
v-model:实现双向绑定

插槽:vue2 使用slot是直接使用slot的,vue3 使用插槽必须为 v-slot

vue2和3的是双向绑定实现方式也不一样

1.数据双向绑定( new proxy() 替代 object.defineProperty() )
Vue3对响应式模块进行了重写,主要修改就是proxy替换了defineProperty实现响应式。
Vue2使用defineProperty存在一些原因:
对数组拦截有问题,需要做特殊处理
不能拦截新增、删除的属性
defineProperty方案在初始化时候,通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法,加载时间有点慢。
Proxy代理
对数组进行拦截,还能对Map,Set实现拦截
proxy是懒处理行为,没有嵌套对象时,不会实施拦截,也使之初始化速度和内存得到改善
proxy存在兼容性问题,IE不支持。
proxy属性拦截原理

function reactive( obj ) {return new Proxy ( obj, {get(target,key){},set(target,key,val) {},deleteProperty(target,key){}}
}
  1. vue3双向绑定优点与vue2双向绑定的缺点
    001: 在vue2之中,假如设置了obj:{a:1} 若是给obj对象添加一个b属性值,直接在methods之中使用方法 obj.b = 2,导致的问题是:数据有更新,但是视图没有更新( 需要使用this.$set()方法去设置b属性为响应式属性值,才能支持试图更新 );vue3之中直接使用reactive定义对象,则当前对象为响应式对象,对于obj.b = 2 视图会更新!
    002: object.defineProperty对于后期添加的属性值是不参与劫持设置为响应式属性的,这就是为什么上面obj.b没有更新视图的缘故
    003: new Proxy对于后期添加的属性值是依旧走proxy内的set和get,这就是obj.b更新视图的缘故

3.vue2与vue3 设置响应式demo

// vue2 设置响应式属性demolet obj = {a: 1,b: 2}let vue = {}for (let k in obj) {Object.defineProperty(vue, k, {get() {console.log('获取了')return obj[k]},set(value) {obj[k] = value}})}console.log('obj', obj) // obj {a: 1, b: 2}vue.c = '000'console.log('vue-c', vue.c) // vue-c 000 没有走 Object.defineProperty这个逻辑console.log('vue-a', vue.a) // 获取了 vue-a 1 打印了,由于有a属性,则走了Object.defineProperty这个逻辑// vue3 设置响应式属性demolet obj = {a: 1,b: 2}let vue = {}vue = new Proxy(obj, {get(target, key, receiver) {console.log('获取了')return Reflect.get(target, key, receiver)},set(target, key, val, receiver) {console.log('设置了')return Reflect.set(target, key, val, receiver)},deleteProperty(target, key) {}})vue.n = '000'console.log('vue-n', vue.n) // vue-c 000 设置了 获取了 vue3之中走了new Proxy的逻辑,设置为了响应式数据

2.v-if和v-show的区别是什么?

切换元素时,v-if会销毁并重建元素,v-show是修改display属性,来做到显示和隐藏。

v-show项目用处:回到顶部组件的显示隐藏,v-if项目用处:登陆方式切换。

3.v-if和v-for的优先级

当 v-if与 v-for 一起使用时,v-for具有比v-if更高的优先级,这意味着v-if 将分别重复运行于每个v-for 循环中。所以,不推荐 v-if 和 v-for 同时使用。如果 v-if 和 v-for一起用的话,vue中的的会自动提示 v-if应该放到外层去。

注意的是:
vue2的时候 v-for指令优先级比v-if高,先执行v-for再执行v-if,而且不推荐一起使用,vue3则再v-for之中使用的时候,把v-if当成一个判断语句,不会互相冲突的

4.v-for中key作用

需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点

Vue3 相比于 Vue2,虚拟DOM上增加 patchFlag 字段。借助Vue3 Template Explorer来看

<div id="app"><h1>vue3虚拟DOM讲解</h1><p>今天天气真不错</p><div>{{name}}</div>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vueconst _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: app }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3虚拟DOM讲解, -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, 今天天气真不错, -1 /* HOISTED */))export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock(div, _hoisted_1, [_hoisted_2,_hoisted_3,_createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */)]))
}

第3个_createElementVNode的第4个参数即 patchFlag 字段类型。
字段类型情况:1 代表节点为动态文本节点,那在 diff 过程中,只需比对文本对容,无需关注 class、style等。除此之外,发现所有的静态节点(HOISTED 为 -1),都保存为一个变量进行静态提升,可在重新渲染时直接引用,无需重新创建。

// patchFlags 字段类型列举
export const enum PatchFlags { TEXT = 1,   // 动态文本内容CLASS = 1 << 1,   // 动态类名STYLE = 1 << 2,   // 动态样式PROPS = 1 << 3,   // 动态属性,不包含类名和样式FULL_PROPS = 1 << 4,   // 具有动态 key 属性,当 key 改变,需要进行完整的 diff 比较HYDRATE_EVENTS = 1 << 5,   // 带有监听事件的节点STABLE_FRAGMENT = 1 << 6,   // 不会改变子节点顺序的 fragmentKEYED_FRAGMENT = 1 << 7,   // 带有 key 属性的 fragment 或部分子节点UNKEYED_FRAGMENT = 1 << 8,   // 子节点没有 key 的fragmentNEED_PATCH = 1 << 9,   // 只会进行非 props 的比较DYNAMIC_SLOTS = 1 << 10,   // 动态的插槽HOISTED = -1,   // 静态节点,diff阶段忽略其子节点BAIL = -2   // 代表 diff 应该结束
}

5.Vue的生命周期

1.vue2生命周期函数
beforeCreate:在实例创建之间执行,数据是未加载状态。
created:在实例创建、数据加载后,能初始化数据,DOM渲染之前执行。
beforeMount:虚拟DOM已创建完成,在数据渲染前最后一次更改数据。el未挂载。
mounted:页面、数据渲染完成。el挂载完毕。可以访问DOM节点。
beforeUpdate:重新渲染之前触发。不会造成重渲染。
Updated:数据已经更新完成,DOM也重新render完成,更改数据会陷入死循环。
`beforeDestroy:实例销毁前执行,实例仍然完全可用。
destroyed:实例销毁后执行,这时候只剩下DOM空壳。
第一次页面加载会触发:beforeCreate, created, beforeMount, mounted。
一般获取数据在 created/beforeMount/mounted中调用, 操作 DOM 在mounted操作
2.vue3生命周期函数
setup 、onBeforeMount 、 onMounted 、onBeforeUpdate 、onUpdated 、onBeforeUnmount、onUnmounted

6.vue3的新Composition API 组合api区别

1.ref和reactive的区别:ref一般用于定义普通数据类型和dom节点,使用 .value去取值 ( toRefs 结构数据,变成响应式数据),reactive一般用于定义复杂数据类型,使用的时候,直接取值即可。源码上的区别,ref若是定义的是简单数据类型,那么响应式原理走的是vue2的Object.defineProperty()的get与set方式,若是ref定义的是引用类型数据,那么响应式原理使用的proxy中Reflect.set与get,reactive响应式原理直接使用的是proxy处理负责数据类型,内部使用了Reflect.get与set实现响应式的。
2.watch和watchEffect的区别:watch侦测一个或者多个响应式数据,并在数据源变化时再调用一个回调函数,watchEffect立即运行一个函数,被动地追踪它的依赖,当这些依赖改变时重新执行该函数

7.vue2每个周期适用场景

beforeCreate: 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法

create: data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作

beforeMount: 执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的

mounted: 执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行

beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步

updated: 页面显示的数据和data中的数据已经保持同步了,都是最新的

beforeDestory: Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁

destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

8.Diff算法

Vue3 patchChildren 源码。结合上文与源码,patchFlag 帮助 diff 时区分静态节点,以及不同类型的动态节点。一定程度地减少节点本身及其属性的比对

function patchChildren(n1, n2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) {// 获取新老孩子节点const c1 = n1 && n1.childrenconst c2 = n2.childrenconst prevShapeFlag = n1 ? n1.shapeFlag : 0const { patchFlag, shapeFlag } = n2// 处理 patchFlag 大于 0 if(patchFlag > 0) {if(patchFlag && PatchFlags.KEYED_FRAGMENT) {// 存在 keypatchKeyedChildren()return} els if(patchFlag && PatchFlags.UNKEYED_FRAGMENT) {// 不存在 keypatchUnkeyedChildren()return}}// 匹配是文本节点(静态):移除老节点,设置文本节点if(shapeFlag && ShapeFlags.TEXT_CHILDREN) {if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {unmountChildren(c1 as VNode[], parentComponent, parentSuspense)}if (c2 !== c1) {hostSetElementText(container, c2 as string)}} else {// 匹配新老 Vnode 是数组,则全量比较;否则移除当前所有的节点if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense,...)} else {unmountChildren(c1 as VNode[], parentComponent, parentSuspense, true)}} else {if(prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {hostSetElementText(container, '')} if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {mountChildren(c2 as VNodeArrayChildren, container,anchor,parentComponent,...)}}}
}

patchUnkeyedChildren 源码如下所示

function patchUnkeyedChildren(c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) {c1 = c1 || EMPTY_ARRc2 = c2 || EMPTY_ARRconst oldLength = c1.lengthconst newLength = c2.lengthconst commonLength = Math.min(oldLength, newLength)let ifor(i = 0; i < commonLength; i++) {// 如果新 Vnode 已经挂载,则直接 clone 一份,否则新建一个节点const nextChild = (c2[i] = optimized ? cloneIfMounted(c2[i] as Vnode)) : normalizeVnode(c2[i])patch()}if(oldLength > newLength) {// 移除多余的节点unmountedChildren()} else {// 创建新的节点mountChildren()}}

9.去除URL中的#

将路由的hash模式改为history模式

10.Vue3事件缓存

Vue3 的cacheHandler可在第一次渲染后缓存我们的事件。相比于 Vue2 无需每次渲染都传递一个新函数。加一个 click 事件。

<div id="app"><h1>vue3事件缓存讲解</h1><p>今天天气真不错</p><div>{{name}}</div><span onCLick=() => {}><span>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vueconst _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: app }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3事件缓存讲解, -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, 今天天气真不错, -1 /* HOISTED */))
const _hoisted_4 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(span, { onCLick: () => {} }, [/*#__PURE__*/_createElementVNode(span)
], -1 /* HOISTED */))export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock(div, _hoisted_1, [_hoisted_2,_hoisted_3,_createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */),_hoisted_4]))
}

观察以上渲染函数,你会发现 click 事件节点为静态节点(HOISTED 为 -1),即不需要每次重新渲染。

11

12.vue-router的两种模式

hash模式: 即地址栏 URL 中的 # 符号
history模式: window.history对象打印出来可以看到里边提供的方法和记录长度。利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法(需要特定浏览器支持)

13.$NextTick

$nextTick是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用

14.Vue-router跳转和location.href有什么区别?

使用 location.href= /url来跳转,简单方便,但是刷新了页面;使用 history.pushState( /url ),无刷新页面,静态跳转;引进 router,然后使用 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。其实使用router跳转和使用 history.pushState()没什么差别的,因为vue-router就是用了 history.pushState() ,尤其是在history模式下

15.vue修饰符

.stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡
.prevent :等同于 JavaScript 中的 event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
.capture :与事件冒泡的方向相反,事件捕获由外到内
.self :只会触发自己范围内的事件,不包含子元素
.once :只会触发一次

16.多根节点

// vue2只能存在一个根节点,需要用一个<div>来包裹着
<template><div><header></header><main></main><footer></footer></div>
</template>
//Vue3 支持多个根节点,也就是 fragment。即以下多根节点的写法是被允许的
<template><header></header><main></main><footer></footer>
</template>

17.vue2组件中data为什么必须是一个函数?

因为 JavaScript 的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。组建中的 data 写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的 data ,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个 data ,这样改一个全都改了。

18.params和query的区别

用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是 this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name 和 this. route.query.namethis.route.params.name 。url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示

19.computed、watch、methods的区别

computed要有返回值,支持缓存。
watch不支持缓存。
methods:不支持缓存。
watch项目用处:搜索框输入框的监听,监听路由地址的改变

20.keep-alive

可以实现组件缓存,当组件切换时不会对当前组件进行卸载
有include、exclude两个属性,可以有条件的进行组件缓存
两个钩子函数activated/ deactivated,用来得知当前组件是否处于活跃状态
keep-alive项目用处:页面跳转保留当前位置。

21.父子组件通信

vue2 父传子,直接props,子传父,采用Emitting Events,this. e m i t ( ‘事件’ , 参数 ) ,父组件访问子组件 emit(‘事件’,参数),父组件访问子组件 emit(事件,参数),父组件访问子组件children(获取全部)、 r e f s (获取指定的),子组件访问父组件 refs(获取指定的), 子组件访问父组件 refs(获取指定的),子组件访问父组件parent、$root(根组件)

vue3 父传子,直接props,子传父,采用Emitting Events,但需要从vue之中解构出defineEmits,再defineEmits(['事件名称‘])
const emit = defineEmits([“change-handerAdd”, “change-handerStep”]);
emit(“change-handerAdd”, id);

22.兄弟组件通信

Vue.prototype.$bus = new Vue()
this.$bus.$emit('data-to-b', 'some data');
this.$bus.$on('data-to-b', this.receiveData);

23.监听组件原生事件

给对应的事件加上native修饰符,才能进行监听

24.单页面应用的优缺点

优点:
良好的交互体验。
良好的前后端工作分离模式。
减轻服务器压力。
缺点:
SEO难度较高。
前进、后退管理。
初次加载耗时多。

25.MVVM

MVVM是Model-View-ViewModel缩写,是把MVC中的Controller演变成ViewModel,Model层代表数据模型,View代表视图UI,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据

26.路由守卫

//全局前置守卫
router.beforeEach((to, from,next) => {// 返回 false 以取消导航return false
})
/* 全局后置守卫 */
router.afterEach((to,from,nex)=>{document.title = to.meta.title;// 1,修改当前页面的标题window.scrollTo(0,0) // 2,每次切换页面的时候,让页面滚动到最顶部})//路由独享守卫// 西瓜播放器页面 beforeEnter介绍{path: '/xgplayer',name: 'Xgplayer',meta: { title: '西瓜播放器' },component: () => import('../views/xgplayer/xgplayer.vue'),/* 路由独享守卫 只在进入路由时触发  不想让进可以直接 return false */beforeEnter: (to, from,next) => {if (to.path == '/login') {next()} else {alert('请登入');next('/login')}},},
//组件内部守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

27.vue2生命周期的理解

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el为undefined,还未初始化。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

28.vue如何获取dom?

先给标签设置一个ref值,再通过this.$refs.domName获取,例如:

<div ref="test"></div>const dom = this.$refs.test

29.v-on可以监听多个方法

<input type="text" v-on="{ input:onInput,focus:onFocus,blur:onBlur, }">

30.assets和static的区别?

这两个都是用来存放项目中所使用的静态资源文件。

两者的区别:
assets中的文件在运行npm run build的时候会打包,简单来说就是会被压缩体积,代码格式化之类的。打包之后也会放到static中。
static中的文件则不会被打包。
建议:将图片等未处理的文件放在assets中,打包减少体积。而对于第三方引入的一些资源文件如iconfont.css等可以放在static中,因为这些文件已经经过处理了。

31.vue初始化页面闪动问题?

使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。

首先:在css里加上以下代码

[v-cloak] {display: none;
}

如果没有彻底解决问题,则在根元素加上style=“display: none;” :style=“{display: ‘block’}”

32.vuex中有几个核心属性,分别是什么?

State:数据唯一来源(数据源),vuex所有的数据都会存在state中,就像一个很大的仓库,存储所有数据,可以实例化用来存储所有的数据,如何存储呢?实际上status就是一个庞大的对象,本身是一个json对象,用来存储所有的数据
Getter:获取数据。本来可以通过state实例化拿到所有数据,但是getter有其存在的道理,好比是vue的computed计算属性,相似性:从现有的state来派生出一个新的state,大大方便我们获取数据,或者state派生出新的状态的时候有很大的作用
Mutation:修改数据,不是通过直接修改,需要通过一个commit
mutation来修改数据,mutation本质上就是一个function,为什么不能直接通过实例化state直接去给state里面的数据做修改,而是通过commit一个mutation,在通过mutation传入一个state,再对state进行修改呢?这里主要是因为,每次提交mutation,都会有一个记录,vue这样做是为了更方便的记录下每一个数据改变的历史和轨迹,方便于监听和回滚之类的操作。还需要注意一点,mutation的操作一定是同步的,写成异步会有很大的麻烦,具体看文档
Action:提交mutation,为什么会多出这个呢?实际上mutation是同步修改数据,而往往业务需求有很多的异步操作,来修改vuex的数据状态,action里面可以进行异步操作,因为我们提交的时候mutation,mutation是通过同步修改数据。Action相当于包装了一层,可以进行任意的异步编程。来提交mutation,在通过mutation同步修改数据

面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。
const store = new Vuex.Store({
modules:{}
})

33.ajax请求代码应该写在组件的methods中还是vuex的actions中?

如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。

如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用

34.vuex中的数据在页面刷新后数据消失问题?

用sessionstorage 或者 localstorage 存储数据
存储: sessionStorage.setItem(‘名’,JSON.stringify(值) )
使用: sessionStorage.getItem(‘名’) —得到的值为字符串类型,用JSON.parse()去引号;

35.怎么在组件中批量使用Vuex的getter属性?

使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中

import {mapGetters} from 'vuex'
export default{computed:{...mapGetters(['total','discountTotal'])}
}

36.组件中重复使用mutation?

使用mapMutations辅助函数,在组件中这么使用

import { mapMutations } from 'vuex'
methods:{...mapMutations({setNumber:'SET_NUMBER',})
}

然后调用this.setNumber(10)相当调用this.$store.commit(‘SET_NUMBER’,10)

37.mutation和action有什么区别?

38.在v-model上怎么用Vuex中state的值?

需要通过computed计算属性来转换

<input v-model="message">
// ...
computed: {message: {get () {return this.$store.state.message},set (value) {this.$store.commit('updateMessage', value)}}
}

39.vue2和vue3响应式原理区别

vue3对于vue2来说,最大的变化就是composition Api 替换了vue2的options Api
vue3的响应式原理替换为了proxy,vue2的则是Object.defineproperty。其中proxy有着以下这些优点:- 1:对象新增的属性不需要使用$set添加响应式,因为proxy默认会监听动态添加属性和删除属性等操作- 2:消除数组上无法监听数组索引、length属性,不再进行数组原型对象上重写数组方法- 3:Object.defineproperty是劫持所有对象的属性设置为getter、setter,然后遍历递归去实现。而proxy则是代理了整个对象。- 4:vue2使用Object.defineproperty拦截对象的getset属性进行操作。而proxy有着13种拦截方法。- 5:由vue2的响应式原理可以看出,vue底层需要对vue实例的返回的每一个key进行getset操作,无论这个值有没有被用到。所以在vue中定义的data属性越多,那么初始化开销就会越大。而proxy是一个惰性的操作,它只会在用到这个key的时候才会执行get,改值的时候才会执行set。所以在vue3中实现响应式的性能实际上要比vue2实现响应式性能要好+ proxy原理- 作用:能够为另外一个对象创建代理,该代理可以拦截和重新定义该对象的基本操作(获取,设置,定义属性等)- proxy的两个参数: 参数1=> 要代理的原始对象; 参数2=>一个对象,这个对象定义了操作将被拦截以及如何重新定义被拦截的操作
``js
const target = {name: "ts",age: 18};
const handler = {};
const proxy = new Proxy(target, handler); // 使用proxy代理了一个空对象 proxy对象具有响应式const target2 = {name: "ts",age: "18"};
const handler2 = {get(target, key, receiver) {console.log(`访问属性${key}`)return Reflect.get(target, key, receiver)},set(target, key, value, receiver) {console.log(`设置属性${key}`)return Reflect.set(target, key, value, receiver)}
};
const proxy2 = new Proxy(target2, handler2); // 使用proxy代理了一个handler2对象 handler2对象中设置了get和set属性
console.log('proxy2.name', proxy2.name)
proxy2.name = 'jkl';
proxy2.sex = 'male';
console.log('proxy2',proxy2);

Object.defineproperty 与 proxy 的区别:由 vue2 的响应式原理可以看出,vue 底层需要对 vue 实例的返回的每一个 key 进行 get 和 set 操作,无论这个值有没有被用到。所以在 vue 中定义的 data 属性越多,那么初始化开销就会越大。而 proxy 是一个惰性的操作,它只会在用到这个 key 的时候才会执行 get,改值的时候才会执行 set。所以在 vue3 中实现响应式的性能实际上要比 vue2 实现响应式性能要好

1:Object.defineproperty 初始化的时候拦截对象,设置为getset属性
const obj = {name: "wxs",age: 25,
};
Object.entries(obj).forEach(([key, value]) => {Object.defineProperty(obj, key, {get() {return value;},set(newValue) {console.log(`监听到属性${key}改变`);value = newValue;},});
});
obj.name = 11;
obj.age = 22;
obj.ak47 = "ak47";1:输出结果 => 监听到属性name改变、监听到属性age改变2: proxy 初始化的时候,有使用这个key值则get一下,有设置这个key值则set一下
const obj = {name:'wxs',age:25
}const prxoyTarget = new Proxy(obj,{get(target,key){return target.key},set(target,key,value){console.log(`监听到属性${key}需要改成${value}`)target[key] = value}
})prxoyTarget.name = 11
prxoyTarget.age = 22
prxoyTarget.ak47 = 'ak47'2:输出结果 => 监听到属性name需要改成11、监听到属性age需要改成22、监听到属性ak47需要改成ak47

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1544620.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

git add成功后忘记commit的文件丢了?

本文目标&#xff1a;开发人员&#xff0c;在了解git fsck命令用法的条件下&#xff0c;进行git add成功但由于误操作导致丢失的文件找回&#xff0c;达到找回丢失文件的程度。 文章目录 1 痛点2 解决方案3 总结/练习 1 痛点 开发过程中&#xff0c;分支太多&#xff08;基线分…

CREO教程——2 绘制标准图纸

CREO教程——2 绘制标准图纸 说明&#xff1a;继承第一章设置好的配置文件&#xff0c;这一章进行学习分享如何定制自己的图纸图框&#xff0c;参考国家标准距&#xff0c;定制属于设计师或单位的通用图框。 1.设置工作目录 1.1设置工作目录 1.打开软件设置工作目录&#x…

u盘格式化怎么恢复数据?四款工具来救急!

工作中真的没少碰到过那些让人头疼的数据丢失问题&#xff0c;特别是U盘里的宝贝数据一不小心就“蒸发”了&#xff0c;简直让人欲哭无泪。不过别担心&#xff0c;我作为一个数据恢复的新手小白&#xff0c;最近可是亲测了几款超给力的数据恢复软件&#xff0c;今天就来跟大家分…

19c-TNS-12541: TNS:no listener

有套19c单机&#xff0c;没应用任何的补丁&#xff0c;使用lsnrctl status查看监听是异常的&#xff0c;但是lsnrctl start发现监听已运行&#xff0c;当前业务连接都正常&#xff0c; orcl:/home/oracledb> lsnrctl status LSNRCTL for Linux: Version 19.0.0.0.0 - Pro…

打造灵活DateTimePicker日期时间选择器组件:轻松实现时间的独立清除功能

element ui中日期和时间选择器&#xff08;DateTimePicker&#xff09;是一个常见且重要的组件。它允许用户轻松地选择日期和时间&#xff0c;极大地提升了用户体验。然而&#xff0c;在某些场景下&#xff0c;用户可能需要更细粒度的控制&#xff0c;例如单独清除已选择的时间…

下载与安装|Inventor 2025百度云资源分享附教程

如大家所了解的&#xff0c;Inventor是一款专业的三维可视化实体建模软件&#xff0c;主要用于各类二维机械制图、三维制图的设计和开发等操作&#xff0c;可以广泛地应用于零件设计、钣金设计、装配设计等领域。 不同领域的应用证明了Inventor具有强大的兼容性&#xff0c;基…

监控易监测对象及指标之:全面监控Oracle ODBC数据库

在数字化时代&#xff0c;数据库作为存储和管理企业核心数据的基石&#xff0c;其稳定性和性能直接关系到业务的连续性和效率。Oracle数据库以其强大的功能和稳定性&#xff0c;广泛应用于各行各业。为了确保Oracle数据库的稳定运行和高效性能&#xff0c;对其进行全面监控显得…

备战软考Day04-计算机网络

1、计算机网络的分类 2、七层网络体系结构 3、网络的设备与标准 4、TCP/IP协议族 TCP/IP作为Internet的核心协议&#xff0c;被广泛应用于局域网和广域网中&#xff0c;目前已成为事实上的国际标准 1、TCP/IP分层模型 TCP/IP协议是Internet的基础和核心&#xff0c;和OSI参考…

git命令将已经commit的代码push到其他分支

文章目录 一&#xff1a;对于多分支的代码库&#xff0c;将提交记录从一个分支转移到另一个分支是常见需求方法1&#xff1a;撤销commit操作方法2&#xff1a;实用命令git cherry-pick 来移动commit 二、不小心revert导致代码消失的问题 一&#xff1a;对于多分支的代码库&…

【Diffusion分割】FDiff-Fusion:基于模糊学习的去噪扩散融合网络

FDiff-Fusion: Denoising diffusion fusion network based on fuzzy learning for 3D medical image segmentation 摘要&#xff1a; 近年来&#xff0c;去噪扩散模型在图像分割建模中取得了令人瞩目的成就。凭借其强大的非线性建模能力和优越的泛化性能&#xff0c;去噪扩散模…

好用的todolist待办清单软件下载推荐

在快节奏的现代生活中&#xff0c;时间管理变得尤为重要。todolist待办清单管理软件&#xff0c;作为一种高效的任务管理工具&#xff0c;它帮助我们记录、跟踪和管理日常任务&#xff0c;从而提升个人效率。 在众多的待办软件中&#xff0c;敬业签以其出色的用户体验脱颖而出…

Vue2电商项目(四) Detail模块

文章目录 一、配置Detail路由1. 将Detail组件配置为路由组件2. 将路由配置文件拆分3. 声明式导航跳转到Detail跳转时存在的问题&#xff1a;页面滚动条还在下边 二、配置API及vuex三、放大镜及下方轮播图1. Detail组件传递放大镜数据2. 读取vuex数据的经典错误undefined3. 放大…

力扣234 回文链表 Java版本

文章目录 题目描述代码 题目描述 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&…

【集合拆分+多线程并行处理,拿来即用】

文章目录 一.业务场景二.拆分流程三. 简单上个List拆分的demo四.测试结果五.小结 一.业务场景 节假日后第一天&#xff0c;上完班有点累&#xff0c;回到家稍微写点简单的东西。 我们项目里面有这样一业务场景&#xff0c;要计算全公司所有人某几个月内每天的考勤机打卡加班工时…

docker从0到1运行mysql(最详细且绝对成功版)

前置环境 CentOS7.8 安装docker yum install -y docker 启动docker并检查docker状态 systemctl start docker systemctl status docker 这样即正常 设置镜像加速 修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值 vim /etc/docker/daemon.json …

set的使用

序列式容器和关联式容器 序列式容器&#xff1a; 前⾯我们已经接触过STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间…

监控和维护 Linux 系统的健康状态:从服务启动故障到操作系统查询

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

启动 Ntopng 服务前需先启动 redis 服务及 Ntopng 常用参数介绍

启动Ntopng服务之前需要先启动redis服务&#xff0c;因为Ntopng服务依赖于redis服务的键值存储。 服务重启 服务启动 Ntopng常用参数&#xff1a; -d 将 Ntopng 进程放入后台执行。默认情况下&#xff0c;Ntop 在前台运行。 -u 指定启动Ntopng执行的用户&#xff0c;默认为…

C++ SLT标准模板简介

STL全称是standard template libaray 标准模板库&#xff0c;这个库是C库中十分重要的一部分&#xff0c;里面涵盖可复用的组件库&#xff0c;而且是一个包罗了数据结构与算法的软件框架。 STL各主要版本 stl库最初是由Alexander Stepanov、Meng Lee在惠普工作室中完成的原始…

Multisim简体中文版百度云下载(含安装步骤)

如大家所熟悉的&#xff0c;Multisim是一款基于电路仿真的软件&#xff0c;可用于电子工程师、电子爱好者和学生进行电路设计、分析和调试。Multisim具有完整的电路设计和仿真功能&#xff0c;可支持模拟电路、数字电路&#xff0c;以及混合电路。 Multisim可以模拟不同电路的…