Vue.js新手必看:了解一下VUE数组的变异方法
Vue框架提供了一些便捷的数组变异方法,包括push、pop、shift、unshift、splice、sort和reverse等。在使用Vue开发Web应用程序时,经常需要对数组进行操作以实现相应的功能,而使用原生的JavaScript数组方法时需要手动更新DOM,显得比较繁琐。Vue的数组变异方法可以自动触发DOM更新,省去了手动更新DOM的步骤,使得开发者可以更加高效地操作数组数据,提高开发效率和代码质量。因此,了解Vue的数组变异方法是非常有必要的。
在Vue中,我们可以使用v-for指令来渲染一个数组。例如:
<template>
<ul>
<li v-for="item in items" :key="item.id">
{{ item }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: ['Apple', 'Banana', 'Orange']
}
}
}
</script>
在上面的例子中,我们使用v-for指令来渲染一个名为items的数组。这个数组包含了三个元素:Apple、Banana和Orange。Vue会自动跟踪每个元素的编号,并在每次数组发生变化时更新DOM。
但是,有时我们需要对数组进行一些操作,例如添加或删除元素。这时,我们就需要使用数组的一些方法,例如push、pop、splice等。但是,这些方法并不会自动触发Vue的DOM更新,因此我们必须手动调用Vue的set或者set或者set或者forceUpdate方法来更新DOM。而Vue提供的变异方法则可以自动触发DOM更新,省略了这些繁琐的步骤。
Vue提供的变异方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
下面我们来详细讲解这些方法是如何工作的。
push方法
Vue的push方法与JavaScript原生的push方法相同,它可以向数组末尾添加一个或多个元素。例如:
this.items.push('Pear');
上面的代码会向数组items中添加一个新元素'Pear'。push方法的返回值是新数组的长度。
当使用Vue的push方法时,它会自动触发DOM更新。这意味着我们不需要手动调用set或者set或者set或者forceUpdate方法来更新DOM。Vue的push方法会在更新DOM前调用数组的原生push方法,并传递相同的参数。当数组发生变化时,Vue会检测到变化并更新DOM。
需要注意的是,如果我们向数组中添加对象类型的元素,那么这个对象必须是响应式的。否则,这个对象的属性变化时不会触发DOM更新。为了避免这种情况,我们应该在添加对象前先使用Vue.set或者this.$set方法将其转换为响应式对象。
pop方法
Vue的pop方法与JavaScript原生的pop方法相同,它可以从数组末尾删除一个元素,并返回被删除的元素。例如:
let lastItem = this.items.pop();
上面的代码会从数组items中删除最后一个元素,并返回该元素。当使用Vue的pop方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
shift方法
Vue的shift方法与JavaScript原生的shift方法相同,它可以从数组头部删除一个元素,并返回被删除的元素。例如:
let firstItem = this.items.shift();
上面的代码会从数组items中删除第一个元素,并返回该元素。当使用Vue的shift方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
unshift方法
Vue的unshift方法与JavaScript原生的unshift方法相同,它可以向数组头部添加一个或多个元素。例如:
this.items.unshift('Grape');
上面的代码会向数组items头部添加一个新元素'Grape'。当使用Vue的unshift方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
splice方法
Vue的splice方法与JavaScript原生的splice方法相同,它可以在任意位置添加或删除一个或多个元素。例如:
this.items.splice(1, 0, 'Kiwi', 'Mango');
上面的代码会从数组items中的索引1位置开始,删除0个元素,并添加两个新元素Kiwi和Mango。当使用Vue的splice方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
需要注意的是,如果我们向数组中添加对象类型的元素,那么这个对象必须是响应式的。否则,这个对象的属性变化时不会触发DOM更新。为了避免这种情况,我们应该在添加对象前先使用Vue.set或者this.$set方法将其转换为响应式对象。
sort方法
Vue的sort方法与JavaScript原生的sort方法相同,它可以按照一定规则对数组进行排序。例如:
this.items.sort();
上面的代码会按照字母顺序对数组items进行排序。当使用Vue的sort方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
需要注意的是,如果我们想要按照自定义的规则对数组进行排序,那么我们需要传递一个比较函数作为sort方法的参数。而这个比较函数不能直接修改数组,否则Vue无法监测到变化。如果需要修改数组,我们应该使用变异方法。
reverse方法
Vue的reverse方法与JavaScript原生的reverse方法相同,它可以将数组中的元素逆序排列。例如:
this.items.reverse();
上面的代码会逆序排列数组items中的元素。当使用Vue的reverse方法时,它会自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。
源码分析
Vue的数组变异方法是在响应式系统中实现的:
-
依赖追踪:当我们访问某个响应式对象的属性时,Vue会自动追踪依赖关系以便监听该属性的变化。
-
数据劫持:Vue使用Object.defineProperty方法来将响应式对象的属性转换为getter和setter,从而实现数据劫持,即当属性发生改变时自动通知依赖更新。
-
观察者模式:在依赖追踪和数据劫持的基础上,Vue通过观察者模式实现了响应式系统的更新机制。当响应式对象的属性发生改变时,观察者会接收到更新通知,然后执行相应的操作,包括更新视图等。
-
数组变异方法:在响应式系统的基础上,Vue实现了一些特殊的数组变异方法,例如push、pop、shift、unshift、splice、sort和reverse等。这些方法能够自动触发DOM更新,从而实现实时更新视图的效果。
Vue提供了一些很方便的数组变异方法,使得我们可以更加轻松地操作数组数据。这些方法自动触发DOM更新,无需手动调用set或者set或者set或者forceUpdate方法。但是需要注意的是,如果我们向数组中添加对象类型的元素,那么这个对象必须是响应式的。否则,这个对象的属性变化时不会触发DOM更新。为了避免这种情况,我们应该在添加对象前先使用Vue.set或者this.$set方法将其转换为响应式对象。
在Vue中,定义了一个全局函数def
,用来定义对象的属性或方法,其源码如下:
export function def(obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
其中,obj
表示要定义属性或方法的对象,key
表示要定义的属性或方法的名称,val
表示要定义的属性或方法的值,enumerable
表示该属性或方法是否可枚举。该函数使用Object.defineProperty
方法将属性或方法转换为getter和setter。
在Vue的响应式系统中,数组变异方法都定义在Array.prototype
上,例如push
、pop
、shift
、unshift
、splice
、sort
和reverse
等。这些方法在内部调用了def
函数来定义数组的属性或方法,并使用dep.notify()
触发依赖更新:
// 定义数组变异方法
const arrayProto = Array.prototype;
export const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
// 缓存原生方法
const original = arrayProto[method];
// 调用数组变异方法时会触发依赖更新
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args);
const ob = this.__ob__;
let inserted;
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
// 对新插入的元素进行响应式处理
if (inserted) ob.observeArray(inserted);
ob.dep.notify();
return result;
});
});
在上述源码中,我们首先使用Object.create
方法创建了一个以Array.prototype
为原型的新对象arrayMethods
,然后遍历数组变异方法并缓存原生方法。
随后,在调用数组变异方法时,会触发依赖更新,并对新插入的元素进行响应式处理。具体来说,当调用push
、unshift
和splice
等方法时,会将新插入的元素转换为响应式对象,并使用ob.observeArray
方法对其进行观测。最后,使用ob.dep.notify()
方法触发依赖更新,通知组件重新渲染视图。
通过这种方式,Vue实现了高效、方便的数组操作方法,在处理数组数据时能够实时更新DOM,提高了开发效率和代码质量。
转载自:https://juejin.cn/post/7247057861129584696