在 JavaScript 中创建任意长度的零填充数组的最有效方法是什么?
let i = 0; Array.from(Array(10), ()=>i++);
ES6 引入了 Array.prototype.fill
。它可以这样使用:
new Array(len).fill(0);
不确定它是否很快,但我喜欢它,因为它很短且可以自我描述。
它仍然不在 IE (check compatibility) 中,但有一个 polyfill available。
尽管这是一个旧线程,但我想在其中添加 2 美分。不知道这有多慢/快,但它是一个快速的单线。这是我所做的:
如果我想预先填写一个数字:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
如果我想预填充一个字符串:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
其他答案建议:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
但如果你想要 0(数字)而不是“0”(字符串中的零),你可以这样做:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
的诀窍吗?因为简单地做 (new Array(5)).map(...) 不会像规范所说的那样工作
new
)当您执行 Array(5)
时,您正在创建一个看起来像这样的对象:{ length: 5, __proto__: Array.prototype }
- 尝试 console.dir( Array(5) )
。请注意,它没有任何属性 0
、1
、2
等。但是当您将 apply
设置为 Array
构造函数时,就像是在说 Array(undefined, undefined, undefined, undefined, undefined)
。你会得到一个看起来像 { length: 5, 0: undefined, 1: undefined...}
的对象。 map
适用于属性 0
、1
等,这就是您的示例不起作用的原因,但是当您使用 apply
时它会起作用。
.apply
的第一个参数实际上是您想要的 this
。对于这些目的,this
无关紧要 - 我们只真正关心 .apply
的参数传播“特征” - 所以它可以是任何值。我喜欢 null
因为它便宜,你可能不想使用 {}
或 []
因为你会无缘无故地实例化一个对象。
简而言之
最快的解决方案:
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
最短(方便)解决方案(小型阵列慢 3 倍,大型阵列稍慢(Firefox 上最慢))
Array(n).fill(0)
细节
今天 2020.06.09 我在 Chrome 83.0、Firefox 77.0 和 Safari 13.1 浏览器上对 macOS High Sierra 10.13.6 进行了测试。我为两个测试用例测试选择的解决方案
小数组 - 有 10 个元素 - 你可以在这里执行测试
大数组 - 有 1M 元素 - 你可以在这里执行测试
结论
基于 new Array(n)+for (N) 的解决方案是小阵列和大阵列的最快解决方案(Chrome 除外,但仍然非常快),建议作为快速跨浏览器解决方案
基于 new Float32Array(n) (I) 的解决方案返回非典型数组(例如,您不能对其调用 push(..)),因此我不会将其结果与其他解决方案进行比较 - 但是此解决方案比其他解决方案快 10-20 倍适用于所有浏览器上的大数组
基于 for (L,M,N,O) 的解决方案对于小型阵列来说很快
基于填充 (B,C) 的解决方案在 Chrome 和 Safari 上速度很快,但在 Firefox 上对于大型阵列的速度却出奇地慢。它们对于小型阵列来说是中等速度
基于 Array.apply (P) 的解决方案为大数组函数 P(n) { return Array.apply(null, Array(n)).map(Number.prototype.valueOf,0) 抛出错误; } 尝试 { P(1000000); } 捕捉(e){ 控制台.错误(e.message); }
https://i.stack.imgur.com/ISmIZ.png
代码和示例
下面的代码介绍了测量中使用的解决方案
函数 A(n) { return [...new Array(n)].fill(0); } function B(n) { return new Array(n).fill(0); } 函数 C(n) { 返回 Array(n).fill(0); } function D(n) { return Array.from({length: n}, () => 0); } function E(n) { return [...new Array(n)].map(x => 0); } // 类型为 function F(n) { return Array.from(new Int32Array(n)); 的数组} 函数 G(n) { return Array.from(new Float32Array(n)); } 函数 H(n) { return Array.from(new Float64Array(n)); // 需要比 float32 多 2 倍的内存 } function I(n) { return new Float32Array(n); // 这不是典型的数组 } function J(n) { return [].slice.apply(new Float32Array(n)); } // 基于 for function K(n) { let a = []; a.长度 = n;让我 = 0;而 (i < n) { a[i] = 0;我++; } 返回一个; } 函数 L(n) { 让 a=[]; for(让 i=0; i
Chrome 的示例结果:
https://i.stack.imgur.com/VRfay.png
let a=[]; for(i=n;i--;) a.push(0);
- 但它比 fill(0)
慢 4 倍 - 所以我什至不会更新那个案例的图片。
for-loop
(N) 在 Safari 中仅比 .fill
(C) 快 1.835,有趣的是,当我现在运行它时,6 个月后,差异已降至仅 1.456 倍。因此对于 Safari,最快的解决方案 (N) 仅比最短和最简单的版本快 45%。道德:坚持使用最短和最简单的版本(对于大多数情况,如果不是所有情况)。它节省了昂贵的开发人员时间,因为它的阅读速度更快,更易于维护,而且随着时间和 CPU 速度的增加,它的回报也越来越多,而无需额外的维护。
用预先计算的值填充数组的优雅方法
这是另一种使用 ES6 的方法,到目前为止没有人提到过:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
它通过将 map 函数作为 Array.from
的第二个参数传递来工作。
在上面的示例中,第一个参数分配了一个包含 3 个位置的数组,其中填充了值 undefined
,然后 lambda 函数将每个位置映射到值 0
。
虽然 Array(len).fill(0)
更短,但如果您需要先进行一些计算来填充数组,它就不起作用了)。
例如,如果您需要一个包含 10 个随机数的数组:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
它比同等的更简洁(和优雅):
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
此方法还可用于通过利用回调中提供的索引参数来生成数字序列:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
奖励答案:使用 String repeat() 填充数组
由于这个答案引起了很多关注,我也想展示这个很酷的技巧。虽然不如我的主要答案有用,但将介绍仍然不太为人所知但非常有用的 String repeat()
方法。这是诀窍:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
酷吧? repeat()
是一种非常有用的创建字符串的方法,该字符串将原始字符串重复一定次数。之后,split()
为我们创建一个数组,然后将其map()
设置为我们想要的值。分步骤分解:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
技巧,但 Array.from()
非常好:-)
已经提到的 ES 6 填充方法很好地解决了这个问题。迄今为止,大多数现代桌面浏览器已经支持所需的 Array 原型方法(Chromium、FF、Edge 和 Safari)[1]。您可以在 MDN 上查找详细信息。一个简单的使用示例是
a = new Array(10).fill(0);
鉴于当前的浏览器支持,除非您确定您的受众使用现代桌面浏览器,否则您应该谨慎使用它。
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
2013 年 8 月添加的注释,2015 年 2 月更新:以下 2009 年的答案与 JavaScript 的通用 Array
类型有关。它与 ES2015 中定义的较新的 typed 数组无关 [现在在许多浏览器中都可用],例如 Int32Array
等。另请注意,ES2015 为 Arrays 和 typed arrays 添加了一个 fill
方法,这可能是填充它们的最有效方法...
此外,它可以对您如何创建数组的某些实现产生很大的影响。尤其是 Chrome 的 V8 引擎,如果它认为可以,它会尝试使用高效的连续内存数组,仅在必要时才转向基于对象的数组。
对于大多数语言,它将是预分配,然后是零填充,如下所示:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
但是,JavaScript 数组 aren't really arrays,它们是键/值映射,就像所有其他 JavaScript 对象一样,所以没有“预分配”要做(设置长度不会分配那么多槽填充),也没有任何理由相信倒数到零的好处(这只是为了使循环中的比较快速)在实现可能已经优化时以相反的顺序添加键不会超过他们处理与数组相关的键的理论通常会按顺序进行。
事实上,Matthew Crumley 指出,在 Firefox 上倒数比倒数要慢得多,我可以确认这一结果——它是数组的一部分(向下循环到零仍然比在 var 中循环到极限要快)。显然,以相反的顺序将元素添加到数组中是 Firefox 上的一个缓慢操作。事实上,结果因 JavaScript 实现而有很大差异(这并不令人惊讶)。这是一个用于浏览器实现的快速而肮脏的测试页面(如下)(非常肮脏,在测试期间不会产生,因此提供的反馈很少,并且会违反脚本时间限制)。我建议在测试之间刷新;如果您不这样做,FF(至少)会减慢重复测试的速度。
在 1,000 到 2,000 个元素数组之间的某个地方,使用 Array#concat 的相当复杂的版本比 FF 上的直接初始化更快。然而,在 Chrome 的 V8 引擎上,每次都是直接 init 胜出……
这是一个测试:
const tests = [ { name: "downpre", total: 0, desc: "倒计时,前递减", func: makeWithCountDownPre }, { name: "downpost", total: 0, desc: "倒计时,后递减decrement", func: makeWithCountDownPost }, { name: "up", total: 0, desc: "Count up (normal)", func: makeWithCountUp }, { name: "downandup", total: 0, desc: "倒计时(for循环)和up(填充)", func: makeWithCountDownArrayUp }, { name: "concat", total: 0, desc: "Concat", func: makeWithConcat } ]; const q = sel => document.querySelector(sel);让标记=“”; for (const {name, desc} of tests) { markup += `
Results:" + "
Length: " + length + "
Loops: " + runCount + "
${test.desc},平均时间:${test.avg}ms
`; } } 结果 += "
如果你使用 ES6,你可以像这样使用 Array.from():
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
具有相同的结果
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
因为
Array.from({ length: 3 })
//[undefined, undefined, undefined]
默认情况下,Uint8Array
、Uint16Array
和 Uint32Array
类将零作为其值,因此您不需要任何复杂的填充技术,只需执行以下操作:
var ary = new Uint8Array(10);
默认情况下,数组 ary
的所有元素都为零。
Array.isArray(ary)
是 false
。该长度也是只读的,因此您不能像 ary.push
那样将新项目推送到它
0
保留为其默认值。
Array.from(new Uint8Array(10))
将提供一个普通数组。
Array(n).fill(0)
慢 5 倍。如果您可以使用 TypedArray,这甚至比 .fill(0)
快得多,特别是如果您可以使用默认的初始值设定项 0
。似乎没有像 C++ std::vector
那样采用填充值和长度的构造函数。似乎对于任何非零值,您都必须构造一个归零的 TypedArray 并 then 填充它。 :/
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
请注意,while
通常比 for-in
、forEach
等更有效。
i
局部变量不是无关的吗? length
是按值传递的,因此您应该能够直接递减它。
arr[i] = value
)分配值非常慢。从头到尾循环并使用 arr.push(value)
会快得多。这很烦人,因为我更喜欢你的方法。
使用对象符号
var x = [];
零填充?喜欢...
var x = [0,0,0,0,0,0];
充满'未定义'......
var x = new Array(7);
带零的 obj 表示法
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
附带说明一下,如果您修改 Array 的原型,
var x = new Array();
和
var y = [];
将有那些原型修改
无论如何,我不会过分关心这个操作的效率或速度,你可能会做很多其他的事情,这些事情比实例化包含零的任意长度的数组更加浪费和昂贵。
null
- var x = new Array(7);
new Array(7)
不创建一个“充满未定义”的数组。它创建一个长度为 7 的 empty 数组。
(new Array(10)).fill(0)
。
我已经在 IE 6/7/8、Firefox 3.5、Chrome 和 Opera 中测试了预分配/非预分配、向上/向下计数和 for/while 循环的所有组合。
下面的函数在 Firefox、Chrome 和 IE8 中一直是最快或非常接近的,并且不比 Opera 和 IE 6 中的最快慢多少。这也是我认为最简单和最清晰的。我发现几个浏览器的 while 循环版本稍快一些,所以我也将其包括在内以供参考。
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
或者
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
声明放入 for 循环的第一部分,仅用逗号分隔。
length
值,这样它就不会不断变化。在我的机器上带来了一个 100 万长度的零数组,从 40ms 到 8。
for (i = 0, array = []; i < length; ++i) array[i] = val;
.. 更少的块? ......无论如何,还有......如果我将新数组的array.length
设置为长度......我似乎在FF中获得了另外10%-15%的速度提升......在Chrome中,它似乎加倍速度-> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(如果我将其保留为 for
循环会更快......但不再需要 init,因此 while
在此版本上似乎更快)
ES6 解决方案:
[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]
const arr = Array.from({ length: 10 }).fill(0);控制台日志(arr)
如果您需要在代码执行期间创建许多不同长度的零填充数组,我发现实现此目的的最快方法是使用本主题中提到的方法之一创建一次零数组,长度为您知道永远不会超过,然后根据需要对该数组进行切片。
例如(使用上面选择的答案中的函数来初始化数组),创建一个长度为 maxLength 的零填充数组,作为需要零数组的代码可见的变量:
var zero = newFilledArray(maxLength, 0);
现在,每当您需要一个长度为 requiredLength < maxLength 的零填充数组时,都对该数组进行切片:
zero.slice(0, requiredLength);
在执行代码期间,我创建了数千次零填充数组,这极大地加快了进程。
function zeroFilledArray(size) {
return new Array(size + 1).join('0').split('');
}
new Array(size+1).join("x").split("x").map(function() { return 0; })
来获取实际数字
new Array(size+1).join('0').split('').map(Number)
使用 lodash 或 underscore
_.range(0, length - 1, 0);
或者如果你有一个数组并且你想要一个相同长度的数组
array.map(_.constant(0));
_.range(0, length, 0)
。 Lodash 不包含最终价值
我不反对:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
由 Zertosh 建议,但在 new ES6 数组扩展中允许您使用 fill
方法本机执行此操作。现在 IE edge、Chrome 和 FF 都支持它,但请检查 compatibility table
new Array(3).fill(0)
会给你[0, 0, 0]
。您可以使用 new Array(5).fill('abc')
之类的任何值(甚至是对象和其他数组)填充数组。
最重要的是,您可以使用填充修改以前的数组:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
这给了你:[1, 2, 3, 9, 9, 6]
创建一个全新的数组
new Array(arrayLength).fill(0);
在现有数组的末尾添加一些值
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
例子
//**创建一个全新的数组** console.log(new Array(5).fill(0)); //**要在现有数组的末尾添加一些值** let existingArray = [1,2,3] console.log([...existingArray, ...new Array(5).fill(0) ]);
我通常这样做(而且速度惊人)的方式是使用 Uint8Array
。例如,创建一个由 1M 个元素组成的零填充向量:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
我是 Linux 用户,一直为我工作,但曾经有一个朋友使用 Mac 有一些非零元素。我以为他的机器出了故障,但仍然是我们找到的最安全的修复方法:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
已编辑
铬 25.0.1364.160
Frederik Gottlieb - 6.43 Sam Barnum - 4.83 Eli - 3.68 Joshua 2.91 Mathew Crumley - 2.67 bduran - 2.55 Allen Rice - 2.11 kangax - 0.68 Tj。克劳德 - 0.67 zertosh - 错误
火狐 20.0
Allen Rice - 1.85 Joshua - 1.82 Mathew Crumley - 1.79 bduran - 1.37 Frederik Gottlieb - 0.67 Sam Barnum - 0.63 Eli - 0.59 kagax - 0.13 Tj。克劳德 - 0.13 zertosh - 错误
缺少最重要的测试(至少对我而言):Node.js 测试。我怀疑它接近 Chrome 基准。
从 ECMAScript2016 开始,大型阵列只有一个明确的选择。
由于这个答案仍然显示在谷歌搜索的顶部附近,这是 2017 年的答案。
这是当前的jsbench,其中包含几十种流行的方法,包括迄今为止针对此问题提出的许多方法。如果您找到更好的方法,请添加、分叉和分享。
我想指出,没有真正最有效的方法来创建任意长度的零填充数组。您可以针对速度进行优化,或者针对清晰度和可维护性进行优化——根据项目的需要,两者都可以被认为是更有效的选择。
在优化速度时,您希望: 使用文字语法创建数组;设置长度,初始化迭代变量,并使用 while 循环遍历数组。这是一个例子。
常量 arr = []; arr.length = 120000;让我 = 0;而 (i < 120000) { arr[i] = 0;我++; }
另一种可能的实现是:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
但我强烈反对在实践中使用第二次植入,因为它不太清楚,并且不允许您在数组变量上维护块范围。
这些比用 for 循环填充要快得多,比标准方法快约 90%
const arr = Array(n).fill(0);
但这种填充方法仍然是较小阵列最有效的选择,因为它清晰、简洁和可维护。除非您制作大量长度为数千或更多的数组,否则性能差异可能不会杀死您。
其他一些重要的注意事项。大多数样式指南建议您在使用 ES6 或更高版本时不要再使用var
,除非有非常特殊的原因。将 const
用于不会重新定义的变量,将 let
用于将要重新定义的变量。 MDN 和 Airbnb's Style Guide 是获取有关最佳做法的更多信息的好地方。这些问题与语法无关,但重要的是,JS 新手在搜索这些新旧答案时了解这些新标准。
没有在答案中看到这种方法,所以这里是:
"0".repeat( 200 ).split("").map( parseFloat )
结果,您将获得长度为 200 的零值数组:
[ 0, 0, 0, 0, ... 0 ]
我不确定这段代码的性能,但如果你将它用于相对较小的数组,这应该不是问题。
new Array(51).join('0').split('')
呢?
.map(function(a){return +a})
?
new Array(51).fill(0)
呢?它提供完全相同的输出。
"0".repeat(100000000).split('');
明显快于所有其他方法。
让填充 = [];填充长度 = 10;填充.填充(0);控制台.log(填充);
在我在 Chrome (2013-03-21) 上的测试中,这个 concat
版本要快得多。 10,000,000 个元素大约需要 200 毫秒,而直接初始化大约需要 675 毫秒。
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
奖励:如果您想用字符串填充数组,这是一种简洁的方法(虽然不如 concat
快):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
我正在测试 TJ Crowder 的出色答案,并提出了基于 concat 解决方案的递归合并,该解决方案优于他在 Chrome 中的任何测试(我没有测试其他浏览器)。
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
使用 makeRec(29)
调用该方法。
值得指出的是,Array.prototype.fill
已作为 ECMAScript 6 (Harmony) proposal 的一部分添加。在考虑线程中提到的其他选项之前,我宁愿使用下面写的 polyfill。
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
最短 for 循环代码
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
安全变量版本
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
,这会更短:for(var a=[];n--;a[n]=0);
我最快的功能是:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
使用本机 push 和 shift 将项目添加到数组中比声明数组范围并引用每个项目来设置它的值要快得多(大约 10 倍)。
仅供参考:当我在 firebug(firefox 扩展)中运行它时,我总是在第一个循环中获得更快的时间,这是倒计时。
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
我很想知道 TJ Crowder 对此有何看法? :-)
while (len--)
来加快速度。我的处理时间从大约 60 毫秒到大约 54 毫秒
我知道我在某个地方有这个原型:)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
编辑:测试
作为对 Joshua 和其他方法的回应,我运行了自己的基准测试,我看到的结果与报告的完全不同。
这是我测试的:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
结果:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
因此,据我估计,通常情况下推送确实较慢,但在 FF 中使用更长的数组时表现更好,但在 IE 中表现更差,这通常很糟糕(令人惊讶)。
b = []...
) 比第一种方法快 10-15%,但比 Joshua 的答案慢 10 倍以上。
this.length
-check 之后包含一个 else {this.length=n;}
。如果需要,这将在将现有数组重新init
化为不同长度 n
时缩短它。
匿名函数:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
用for循环稍微短一点:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
适用于任何 Object
,只需更改 this.push()
中的内容。
您甚至可以保存函数:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
调用它使用:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
将元素添加到已经存在的数组中:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
性能:http://jsperf.com/zero-filled-array-creation/25
'0 '.repeat(200).split(' ')
new Array(len)
非常缓慢。(arr = []).length = len; arr.fill(0);
是我在任何地方看到的最快的解决方案......或者至少并列arr = Array(n)
和(arr = []).length = n
根据规范表现相同。在某些实现中,可能会更快,但我不认为有很大的不同。arr.fill(0)
...一切都发生了变化。现在,在大多数情况下使用new Array()
会更快,除非您获得数组大小 > 100000...然后你可以再次开始看到速度增加。但是,如果您实际上不必用零预填充它并且可以使用空数组的标准错误。然后(arr = []).length = x
在我的测试用例中大部分时间都快疯了。new Array(5).forEach(val => console.log('hi'));
与new Array(5).fill(undefined).forEach(val => console.log('hi'));
。fill()
比 for 循环慢很多:jsperf.com/zero-filling-large-arrays 而且new Array(n)
和a = []; a.length = n
之间没有显着差异