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){}}
}
- 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.name和this.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拦截对象的get和set属性进行操作。而proxy有着13种拦截方法。- 5:由vue2的响应式原理可以看出,vue底层需要对vue实例的返回的每一个key进行get和set操作,无论这个值有没有被用到。所以在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 初始化的时候拦截对象,设置为get和set属性
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
相关文章:
vue基础面试题
1.Vue指令 v-bind:动态绑定数据 v-on:绑定事件监听器 v-for:循环指令,可以循环数组或对象 v-if:根据表达式的真假值,判断是否渲染元素,会销毁并重建 v-show:显示隐藏元素࿰…...
关系型数据库和非关系型数据库的区别
1.常见的主流数据库 关系型数据库: MySql 、达梦 、PostgreSQL 、Oracle 、Sql Server 、Sqlite非关系型数据库: Redis 、MongoDB 、HBase 、 Neo4J 、 CouchDB 2.介绍 关系型数据库最典型的数据结构是表,由二维表及其之间的联系…...
学习之什么是迭代器
什么是迭代器 迭代器的作用:访问容器中的元素 首先要了解什么是Iterablelterable(可迭代的) 字符串、列表、元组、字典都是lterable,都可以放到for循环语句中遍历 lterable类型的定义中一定有一个_iter_方法iter 方法必须返回一个lterator(迭代器) 可以…...
数据结构-3.6.队列的链式实现
队列可以理解为单链表的阉割版,相比单链表而言,队列只有在添加和删除元素上和单链表有区别 一.队列的链式实现: 1.图解: 2.代码: #include<stdio.h> typedef struct LinkNode //链式队列结点 {int data;st…...
Java中去除字符串中的空格
在平时的开发中,在后端经常要获取前端传过来的字符串,有的是用户从输入框中输入的,有的是通过excel表格中获取的。 在这些字符串中,有时候会遇到字符串中有空格、换行符或者制表符,对于这种字符串来说,直接…...
AI大模型算法工程师就业宝典—— 高薪入职攻略与转行秘籍!
从ChatGPT到新近的GPT-4,GPT模型的发展表明,AI正在向着“类⼈化”⽅向迅速发展。 GPT-4具备深度阅读和识图能⼒,能够出⾊地通过专业考试并完成复杂指令,向⼈类引以为傲的“创造⼒”发起挑战。 现有的就业结构即将发⽣重⼤变化&a…...
node-rtsp-stream、jsmpeg.min.js实现rtsp视频在web端播放
1. 服务地址(私有):https://gitee.com/nnlss/video-node-server 2.node-rtsp-stream 需要安装FFMPEG; 3.给推拉流做了开关,可借助http请求,有更好方式可联系; 4.存在问题: 1&…...
C++ 9.27
作业: 将之前实现的顺序表、栈、队列都更改成模板类 Stack #include <iostream> using namespace std; template <typename T> class Stack { private: T* arr; // 存储栈元素的数组 int top; // 栈顶索引 int capacity; // 栈的…...
让具身智能更快更强!华东师大上大提出TinyVLA:高效视觉-语言-动作模型,遥遥领先
论文链接:https://arxiv.org/pdf/2409.12514 项目链接:https://tiny-vla.github.io/ 具身智能近期发展迅速,拥有了大模型"大脑"的机械臂在动作上更加高效和精确,但现有的一个难点是:模型受到算力和数据的制…...
Excel 获取某列不为空的值【INDEX函数 | SMALL函数或 LARGE函数 | ROW函数 | ISBLANK 函数】
〇、需求 Excel 获取某列不为空的值(获取某列中第一个非空值 或 获取某列中最后一个非空值)。 一、知识点讲解 INDEX函数 和 SMALL函数 两个函数搭配使用都可以实现上述需求 获取某列中第一个非空值 。 INDEX函数 和 LARGE函数 两个函数搭配使用都可以实现上述需求 获取某…...
爆火!大模型算法岗 100 道面试题全解析,赶紧收藏!
大模型应该是目前当之无愧的最有影响力的AI技术,它正在革新各个行业,包括自然语言处理、机器翻译、内容创作和客户服务等等,正在成为未来商业环境的重要组成部分。 截至目前大模型已经超过200个,在大模型纵横的时代,不…...
Python画笔案例-068 绘制漂亮米
1、绘制漂亮米 通过 python 的turtle 库绘制 漂亮米,如下图: 2、实现代码 绘制 漂亮米,以下为实现代码: """漂亮米.py注意亮度为0.5的时候最鲜艳本程序需要coloradd模块支持,安装方法:pip install coloradd程序运行需要很长时间,请耐心等待。可以把窗口最小…...
得物App荣获国家级奖项,正品保障引领潮流电商新风尚
近日,在2024年中国国际服务贸易交易会上,得物App凭借其在科技创新保障品质消费领域的突出成果,再次荣获国家级殊荣——“科技创新服务示范案例”。这是继上海市质量金奖之后,得物App获得的又一个“高含金量”奖项。 作为深受年轻人…...
【BurpSuite】SQL注入 | SQL injection(1-2)
🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍收藏💗支持一下哦 【BurpSuite】SQL注入 | SQL injection(1-2) 实验一 Lab: SQL injection vulnerability in WHERE clause…...
ThreadPoolExecutor有哪些核心的配置参数?
ThreadPoolExecutor 是 Java 中强大的线程池实现,具有多种配置参数,可以灵活地根据具体应用需求进行调整。以下是 ThreadPoolExecutor 的核心配置参数及其简要说明: 1. corePoolSize 描述:核心线程池的大小,即最小保…...
关于工作虚拟组的一些思考
这是学习笔记的第 2493篇文章 因为各种工作协作,势必要打破组织边界,可能会存在各种形态的虚拟组。 近期沉淀了一些虚拟组的管理方式,在一定时间范围内也有了一些起色,所以在不断沉淀的过程中,也在不断思考。 这三个虚…...
【Redis入门到精通六】在Spring Boot中集成Redis(含配置和操作演示)
目录 Spring Boot中集成Redis 1.项目创建和环境配置 2.基本操作演示 Spring Boot中集成Redis Spring社区也自定义了一套Redis的客户端,与jedis的操作方式有所差异,Spring中把每个类型的操作都单独封装了起来。下面就让我来带大家了解如何在Spring Boot…...
【CSS】透明度 、过渡 、动画 、渐变
opacity 透明度transition 过渡animation 动画background 渐变 ( 线性渐变 \ 径向渐变 \ 锥形渐变 ) opacity 透明度 设置元素的透明度,会影响元素及其所有子元素的透明度,值范围:0(完全透明)到 1(完全不透…...
尚硅谷vue3+TypeScript笔记大全
1. Vue3简介 2020年9月18日,Vue.js发布版3.0版本,代号:One Piece(n 经历了:4800次提交、40个RFC、600次PR、300贡献者 官方发版地址:Release v3.0.0 One Piece vuejs/core 截止2023年10月,最…...
New major version of npm available! 8.3.1 -> 10.8.3 报错
问题 npm install 安装新项目时,出现如下升级错误。 npm notice npm notice New major version of npm available! 8.3.1 -> 10.8.3 npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.3 npm notice Run npm install -g npm10.8.3 to upd…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
