首页 > 代码库 > vue 数组

vue 数组

今天项目中发现的一个问题:

技术分享

在vue项目中输出一个数组,明明有俩个值:0,6,但是length为1

技术分享

正常的是这样的

结果研究发现,是vue源码的问题,具体内容如下:

 

转载自:http://www.cnblogs.com/Darlietoothpaste/p/6682407.html

Vue的数组操作的实现代码大致如下:

 1 const aryMethods = [push, pop, shift, unshift, splice, sort, reverse];
 2 const arrayAugmentations = [];
 3 
 4 aryMethods.forEach((method)=> {
 5 
 6     // 这里是原生Array的原型方法
 7     let original = Array.prototype[method];
 8 
 9    // 将push, pop等封装好的方法定义在对象arrayAugmentations的属性上
10    // 注意:是属性而非原型属性
11     arrayAugmentations[method] = function () {
12         console.log(我被改变啦!);
13 
14         // 调用对应的原生方法并返回结果
15         return original.apply(this, arguments);
16     };
17 
18 });
19 
20 let list = [a, b, c];
21 // 将我们要监听的数组的原型指针指向上面定义的空数组对象
22 // 别忘了这个空数组的属性上定义了我们封装好的push等方法
23 list.__proto__ = arrayAugmentations;
24 list.push(d);  // 我被改变啦! 4
25 
26 // 这里的list2没有被重新定义原型指针,所以就正常输出
27 let list2 = [a, b, c];
28 list2.push(d);  // 4

在Vue的官方文档中,有着如下的提示:

  1. 当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如: vm.items.length = newLength

这个是Js语法的限制,什么限制呢?

先来看一下,在这篇文章中写到,为什么不利用如下的代码来实现:

 1 function FakeArray() {
 2   return  Array.call(this,arguments);
 3 }
 4 
 5 FakeArray.prototype = [];
 6 FakeArray.prototype.constructor = FakeArray;
 7 
 8 FakeArray.prototype.push = function () {
 9     console.log(我被改变啦);
10     return Array.prototype.push.call(this,arguments);
11 };
12 
13 let list = [a,b,c];
14 
15 let fakeList = new FakeArray(list);

然而,作者在测试代码的时候,发现fakeList实际上是一个数组,而且它的push是内置的push方法,并不是继承FakeArray的方法。

在作者文章的评论中,有个网友评论说,这是因为Array.call并不会引用this,不止Array,String,Number,Regexp,Object等等JS的内置类都不行。

所以实际上代码是这样的:

function FakeArray() {
  return  Array(arguments);
}

这也就是ES5以下无法完美继承数组的问题,回过头看一下Vue中的实现,Vue的作者用的是__proto__属性,该属性指向构造对象的原型。

也就是说,上面的例子我们可以这样改写:

 1 function FakeArray() {
 2   var x =  Array.call(null,arguments);
 3    x.__proto__ = FakeArray.prototype
 4    return x;
 5 }
 6 
 7 FakeArray.prototype = [];
 8 FakeArray.prototype.constructor = FakeArray;
 9 
10 FakeArray.prototype.push = function () {
11     console.log(我被改变啦);
12     return Array.prototype.push.call(this,arguments);
13 };
14 
15 let list = [a,b,c];
16 
17 let fakeList = new FakeArray(list);

但是呢,这样写,也就意味着我们不能检测到length,和fakeList[x] = 1;这样的操作,也就有了Vue文档中的提示了。

本文参考自https://github.com/youngwind/blog/issues/85及其评论。

vue 数组