如何在JavaScript中连接两个数组?

7
我看到了这个response,用于将一个数组扩展到另一个数组中,所以我尝试了一下:
console.log(['a', 'b'].push.apply(['c', 'd']));

但它打印出来的是:
2

不应该打印出来吗?
['a', 'b', 'c', 'd']

如果不是这样,那我做错了什么?

2
请查看此处 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/concat - elclanrs
Array.prototype.push.apply(ABArray, CDArray) - Ram
7个回答

17

试一下这个:

 console.log(['a', 'b'].concat(['c', 'd']));

17

如果不行,我做错了什么?

首先,.push方法返回数组的新长度

var arr = [1, 1, 1];
console.log(arr.push(1)); // 4
console.log(arr); // [1, 1, 1, 1]

第二,.apply 需要两个参数:你想要将函数应用到的对象和一个参数数组。但是你只传递了一个参数,因此你的代码基本上等价于:
['c', 'd'].push()

也就是说,你没有向['c', 'd']数组中添加任何内容。这也解释了为什么输出中看到了2['c', 'd']的长度是2,而.push()不会添加任何元素,所以它仍然是长度为2的数组。

如果你想使用.push来改变原始数组(而不是像.concat一样创建一个新数组),那么它应该是这样的:

var arr = ['a', 'b'];
arr.push.apply(arr, ['c', 'd']); // equivalent to Array.prototype.push.apply(arr, [...])
//              ^   ^--------^
//    apply to arr   arguments
console.log(arr); // ['a', 'b', 'c', 'd']

另请参阅


也许这个例子更清晰:[].push.apply(arr, ['c', 'd']); - maioman
1
我同意,但是我不喜欢不必要地创建数组 ;) - Felix Kling

16
如果你的场景允许使用ES6语法,你可以使用扩展运算符来连接数组。
var arr1 = [1,2];
var arr2 = [3,4];
var arr3 = [...arr1, ...arr2];
console.log(arr3); // Logs [1,2,3,4]

1
我们可以称之为“扩展元素”吗?它不是一个运算符(即使你在某些地方看到这样的说法)。 - Felix Kling
2
更新为 spread element。对于任何感兴趣的人,Spread Element 是 ES6 规范中使用的措辞。您可以在 Expressions section 中查看它。向下滚动一点到 _SpreadElement_。你知道的越多! - Jonathan Michalik

5

如果您正在使用现代浏览器,那么可以使用扩展运算符...,例如:

console.log([...['a', 'b'], ...['c', 'd']])

如果您使用的是旧版浏览器/没有转译器,那么concat是最佳选择。
console.log(['a', 'b'].concat(['c', 'd']))

3
由于各种数组添加方法的使用存在普遍误解,因此我将介绍一种最安全的替代方法,以应对ES6引入扩展运算符的情况。 函数式语言 函数式语言的开发旨在简化代码开发,允许程序员和系统工程师定义函数来替换常见操作/算法。 JS是一种函数式语言,您编写函数可以使生活更轻松,节省您的输入时间,并使程序易于测试和验证,那么为什么要用危险的替代方案呢?
答案中出现的错误(除了Jonathan Michalik的回答外)是它们都试图强制语言做一些应该由函数(Function.apply)完成的事情,或者提供一个没有解释其操作的解决方案(Array.concat)。
例如,编写一个函数来追加数组。
function appendArray(array,array1){ // adds the items in array1 
                                    // array1 can be any type
                                    // to the end of array 
    var len,i;
    array1 = [].concat(array1);   // ensure array1 is an array
    len = array1.length;
    i = 0;
    while(i < len){
        array[array.length] = array1[i++]; // this is 2* quicker than invoking push
    }
    return array;
}

只需花60秒钟的时间编写代码,或者在您创建的通用库中添加此功能,就可以创建一个安全且可用于各种场景的数组追加函数。

log(appendArray([0, 1, 2, 3], 4)); // 0,1,2,3,4
log(appendArray([0, 1, 2, 3], [4, 5, 6])); // 0,1,2,3,4,5,6

现在来谈为什么其他答案不是好的解决方案。 Array.concat 是更安全的选项,如果您可以控制对数组的所有引用,则应该使用它。但它的缺点是在使用时会创建一个新的数组。
var array1 = [1,2,3];
var array2 = [4,5,6];
array1 = array1.concat(array2); // 1,2,3,4,5,6

许多人错误地认为 concat(array2)被添加到 array1 中,实际上它是被添加到 array1 的副本中。如果您有对原始数组的其他引用,则最终会创建一个连接数组的副本,而原始数组仍然存在于内存中。
function doSomething(array){
    ... generate some info
    array.concat(info);
}

var myArray = [...someData];  // the array
var myObject.setArray(myArray); // create a new referance to the array in myObject
myArray = doSomething(myArray);  // adds info via concat to the array.

虽然不是显而易见,但您现在有两个数组:一个原始的数组在myObject内部,以及在myObject中连接版本的数组,它可能在闭包中存储数组引用,除非您取消关联所有相关上下文,否则您不能更改或删除它。也无法知道原始数组存在多少引用。

Function.apply()

有许多理由不使用此函数,但特别值得注意的是在Array.push函数上使用它。如果您没有对数组进行类型检查,则会遭受不确定性。

var myArray = [1,2,3,4];
var data = getSomeData(); // may return array or array like data
myArray = doSomeWorkOn(myArray); // the spec says this may return undefined
myArray.push.apply(myArray,data); // what happen here is indeterminate and
                                     // depends on the JS context, the JS mode
                                     // and the JS version

如果没有对myArray进行undefined的审查,您无法预测apply的结果。它可能会引发错误,或者如果全局范围具有push函数并且未处于严格模式,则可能会默默失败。

不知道JS版本ES5还是ES6,apply可能已将一个对象data推送到myArray中,也可能将data中的所有项ES5不将类似数组的对象识别为Function.apply数组,而ES6则可以。因此,必须审查myArraydata以使其成为当前JS版本的正确类型。

参数具有依赖于当前JS上下文的限制,JS上下文处理长参数列表时也存在不一致性。有些会引发错误,而另一些则仅简单截断参数。

var myPixelData = [];
myPixelData.push.apply(myPixelData,getSomePixelData()); // what will happen????

这段代码可能会抛出异常,也可能正常执行,或者只将65535个项推入数组中,可能更多,也可能更少。你需要在try catch块中调用它,并将结果与getPixelData返回的数组长度进行比较。所有这些额外的复杂性只是为了使它更容易吗?
那么为什么要在Array.push上使用Function.apply,或者使用Array.concat,当编写一个函数以执行所需操作并避免一长串问题、歧义和错误更容易呢?

1

你应该这样使用变量

 <script type="text/javascript">
 var arr1=['a', 'b'];
 var arr2=['c', 'd'];
 Array.prototype.push.apply(arr1, arr2);
  console.log(arr1);
 </script>


这是一个不太正规的解决方案。 - Matías Fidemraizer
@Matías:你为什么这么想? - Felix Kling
因为有比调用原型函数更好的解决方案...请查看其他答案以获取更多详细信息。 - Matías Fidemraizer
@MatíasFidemraizer:“更好”是指什么?仅仅因为有“更好”的解决方案并不意味着这个解决方案是hacky的。你一直在调用原型函数!Array.prototype.push[].push是同一个函数。 - Felix Kling
只有在希望更改函数调用中的 this 值时才应使用 Apply。如果您不检查第一个参数是否为 null 或 undefined(如果您不使用严格模式),则只是在堆栈上添加了一个额外的调用,没有任何好处,并且还存在污染全局对象的风险。 - Blindman67
显示剩余3条评论

1
你应该尝试这个:

a= ['a', 'b'];
b= ['c', 'd'];
a.push.apply(a,b);

console.log(a);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接