Vue2不能检测对象属性的添加、删除
Vue2不能检测数组的项修改(添加,删除,修改)
解决方式
方式一
// $set是Vue.set的别名
this.$set(this.obj, k, v)
Vue.set(this.obj, k, v)
this.$delete(this.obj, k)
Vue.delete(this.obj, k)
方式二
//使用数组的操作函数(其实已被Vue进行了修改)
splice(),push(), pop(),shift(), unshift(),sort(), reverse()
整体代码测试案例
<template>
<div class="home">
<div>数组:{{ arr }}</div>
<div>对象:{{ obj }}</div>
<button @click="changeArr">点我更改数组(不会触发响应式)</button>
<button @click="changeArr1">点我更改数组(会触发响应式)</button>
<button @click="changeObj">点我删除对象(会触发响应式)</button>
<button @click="changeObj1">点我新增对象(会触发响应式)</button>
</div>
</template>
<script>
import Vue from "vue";
export default {
data() {
return {
arr: [1, 2, 3, 4, 5],
obj: {
name: "张三",
age: 19,
},
};
},
methods: {
changeArr() {
this.arr[0] = 234;
// this.arr[this.arr.length] = 666;
console.log(this.arr); //我们已经触发事件改变了 但是它页面没有响应式 所以我们用到了vue2的方法
},
changeArr1() {
// this.arr.pop(); //使用数组方法触发响应式
/*
this.arr.splice(1, 1, 4);//第一个为起始,替换一个,替换值为4
this.arr.reverse();//反转数组
this.arr.shift();//前删
this.arr.pop();//尾删
this.arr.unshift(8);//前插元素
this.arr.push(5);//尾部添加元素
this.arr.sort();//从小到大排序
*/
// this.$set(this.arr, 0, 234); //修改数组元素
this.$set(this.arr, this.arr.length, 666); //新增数组元素
// this.$delete(this.arr, 0);//删除数组元素是0的
console.log(this.arr);
},
changeObj() {
//对象的删除方法
this.$delete(this.obj, "sex");
},
changeObj1() {
//对象的新增方法
this.$set(this.obj, "sex", "女");
// this.obj.name = "男";
},
},
};
</script>
面试三连问
1、 为啥vue2的修改数组的索引不会触发响应式,但是修改对象的属性却可以触发响应式?
在JavaScript中,数组本质上是一种特殊类型的对象,其索引作为键。然而,当我们直接通过索引来修改数组元素,比如 arr[0] = ‘new value’,这个操作并没有触发JavaScript的常规属性访问器(getter和setter)。在非严格意义上讲,这是因为数组的索引访问并不是通过属性访问器实现的,而是语言规范中的一种特殊行为。
原理:Vue.js利用了Object.defineProperty方法来劫持(即拦截)对象属性的访问和修改,从而实现数据的响应式。这个方法允许你定义一个对象属性的getter(获取属性值时调用的函数)和setter(设置属性值时调用的函数)。当属性被访问或修改时,Vue可以通过这些getter和setter来追踪变化,并执行相应的更新操作。
但是,直接通过数组索引修改元素值的方式绕过了Vue设置的getter和setter,因为这不属于Object.defineProperty直接管理的属性访问方式。因此,Vue无法得知数组的这个变化,也就不会触发视图的更新。
2、为啥vue3就解决了这个问题?
Vue 3 解决了这个问题主要是因为它采用了不同的响应式机制——Proxy。相比于Vue 2中基于Object.defineProperty的响应式系统,Vue 3中的Proxy提供了更全面的陷阱(traps),可以拦截对象上几乎所有的访问和修改操作,包括数组索引的修改和长度的更改。
原理:Proxy 是ES6引入的一个新特性,它允许你创建一个对象的代理,用来“代理”对目标对象的各种操作。Proxy可以定义一组拦截器( traps),这些拦截器可以监听并控制目标对象上的各种访问和修改行为,比如get(获取属性值)、set(设置属性值)、has(检查属性是否存在)、deleteProperty(删除属性)等。
Vue 3 利用Proxy来创建一个代理,将数据包装起来。当数据被访问或修改时,Proxy的陷阱会被触发,Vue就可以在这个过程中记录变化、执行依赖更新逻辑等。由于Proxy是直接在对象层级进行拦截,无论是对象属性的添加、删除还是数组元素的修改,甚至是迭代器的使用,Vue 3 都能一一捕获到,因此极大地增强了响应式的灵活性和全面性。
3、那为啥vue2的对象删除不能触发响应式
Vue 2 使用 Object.defineProperty 在数据对象的每个响应式属性上设置 getter 和 setter。这些 getter/setter 能够在属性访问和修改时通知 Vue,触发视图更新。但是,当删除一个属性时,这个操作并不经过 getter 或 setter,因此 Vue 无法知道属性已被删除。
Vue 2 在实例初始化时会遍历 data 对象的所有属性,并将其转换为响应式的。这意味着只有在初始化阶段存在的属性才会被跟踪。如果在实例创建后动态添加或删除属性,Vue 的响应式系统默认是无法识别这些变化的。