一些关于创建和克隆数组的小tips。
在javascript中,没有太多复杂的数据类型,只会看见array和object。 然而,在es6中,加入了几个数据类型和数据结构,如:symbol,set,和map。
array 在javascipt中是类似拥有长度的一个对象列表,可以用数字当做索引。
在此文章中,我将会分销一些关于创建新数组和克隆数组的小技巧
创建数组:使用数组构造器
最流行创建数组的方式是使用字面量语法,这种方式非常直观。然而,当你想要创建一个动态数组的时候,或许这个字面量语法方式就不是最佳的选择了。这里有一种可选方式,就是使用数组构造器。
array构造器接受不同的参数去创建不同的数组。
创建带有长度的数组
我们可以看到当给出数组长度去创建数组会发生了什么。这个构造器会根据给出的长度去设置长度属性,但是没有赋值元素。
从以上片段,你就可以看到在数组中的每一个元素都被赋值成了undefined。实际上,这些元素值是从来没有被赋值的。
下图将这个问题说的更为清楚:
这就会有一个问题,在此数组上使用map,filter,reduce等方式去操作数组是没有任何意义的。如果我们让想设置5为默认数组元素值,可以尝试以下:
我们可以看到map是没有起作用的,因为这个索引此index元素是不存在的,只有length 属性存在而已。
我们可以尝试使用其他方式来修复此问题。
1.使用Array.prototype.fill()
这个fill() 方法将会填满数组的每个元素,从开始到结束,设置一个静态值。这最后一个index索引是不包括的。你可以学到更多关于 fill() 方法。
简单的代码示例:
这里我们填满所有的元素使用元素值5,你也可以使用fill() 设置每个元素为不同的值。
2.使用 Array.from()
from() 方法就是从一个数组或迭代对象里创建一个新的,浅拷贝的数组实例。你可以学习更多关于的from()方法。
注意:Array.from() 只在支持es6的浏览器里起作用。
以下是简单的代码片段:
这里,使用Array.from() 我们现在有真的undefined值设置在每个数组元素里。这就意味着我们可以使用map() 和 filter()去操作数组,是因为index属性存在。
还有一件事更值得注意的是,Array.from() 函数是可以接受第二个参数的,比如使用map函数。它可以对每一个元素进行回调。在Array.from() 之后再去调用map()函数是多余的。
以下是简单的例子:
3. 使用展开操作符
展开操作符(...),是es6新增的,数组中可以展开数组元素,设置缺少的元素为undefined。这个产生的结果就跟Array.from()的结果是一样的,而且只使用array作为唯一的参数。
以下简单的代码片段:
你也可以在数组上使用方法像map 和 filter, 是因为index属性是已经存在了的。
4.利用 Array.of()
如你所见,我们可以使用数组构造器或者其他方式去创建一个新数组,Array.of() 就比较时尚一点了。 实际上,Array.of() 与Array唯一的区别就是如何处理传递给它们的整数。
当Array.of(5) 创建一个新数组,传递给它的参数是5的时候,只会默认为length为1,此元素值是5。而Array(5) 就会创建一个空新数组,带有5个不存在的元素,并且设置此数组长度的元素为5.
var array1 = Array.of(5); // [5]
var array2 = Array(5); // Array(5) {length: 5}
另外更主要不同的地方是,Array.of的表现更像Array的构造器。你可以学到更多关于Array.of().
转换为数组:
如果你长时间都使用JavaScript,那你应该知道arguments对象,即使此对象参数是与数组对象类似,并且能够在每个函数中保存下接受的参数列表。即使这个arguments对象非常像数组,但是它不能使用Array.prototype原型上的方法的。
在es6之前,你将会看到以下的代码片段尝试将arguments对象转化为一个数组:
现在使用Array.from() 或者 展开操作符,你可以很方便的将数组转化为一个对象。因此,可以如下做:
var args = Array.prototype.slice.call(arguments);
//也可以这么做
// Using Array.from()
var args = Array.from(arguments);
// Using the Spread operatorvar
args = [...arguments];
这些也可以用于迭代器,如以下所示:
克隆数组
在JavaScript中,数组和对象都是引用类型。这就意味着一个变量定义为数组或者对象的时候,此变量其实是储存的在内存中的一个位置。
数组,就跟JavaScript中的其他对象一样的。这就意味着复制数组是复制的内存引用位置而不是值。
引用类型就是存储的指针,以下代码的就很好的说明这个问题:
1.相似的数组不相等
可以看到array1与array2是一样的元素值与长度,但是它们是不相等的。每个数组的指针引用的是不同的内存位置。
2.复制数组其实就是复制了指针位置而不是值
现在,我们尝试将array1数组复制到array2上,但是我们只是将array2的指针指向了array1。因此,array1和array2的在内存中的位置是相等的。
所以当我们操作array2移除掉最后一个元素的时候,array1也是做出了相同的改变。就只是因为它们是同一个指针。
克隆数组的Hack:
1.使用数组方法:Array.prototype.slice()
slice方法创建一个浅拷贝的数组。关于slice。
使用slice()或者slice(0) ,就可以达到这个目的。
// with O as only argumentarray.slice(0);
// without argumentarray.slice();
以下是简单的代码片段:
这里的array2克隆的array1是同样的元素和长度。然而,它们都指向的是内存中不一样的位置,所以也不相等。也可以注意到我们改变了array2,而array1是没有任何变化的。
2.使用数组方法:Array.prototype.concat()
concat() 方法是用来合并两个及其更多数组的,最后成为一个新数组,但原始数组是没有被改变的。关于concat()
这个技巧就是使用concat([]) 或者 concat()
// with an empty arrayarray.concat([]);
// without argumentarray.concat();
concat与slice上克隆数组感觉是很相似的,以下代码使用concat克隆数组:
3.使用数组方法:Array.from()
就像我们之前所见,Array.from() 可以从原数组上创建一个浅拷贝的新数组。以下代码示例:
4. 利用数组解构
在es6中有更多更强大的工具,例如解构,展开,箭头函数等等。解构是一个非常强大的工具解析复杂的类型例如数组和对象。
这个小技巧就是利用rest参数,这就涉及到解构和展开操作符,以下代码片段示例:
let [...arrayClone] = originalArray;
以上代码就是创建一个变量名为arrayClone,它克隆于originalArray。以下代码片段示例,如何利用数组解构去克隆数组。