创建零填充JavaScript数组的最有效方法?

在JavaScript中创建任意长度的零填充数组的最有效方法是什么?

569324 次浏览

使用对象符号

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 = [];

会有那些原型修改

无论如何,我不会过度关注这个操作的效率或速度,您可能会做很多其他事情,这些事情比实例化一个包含零的任意长度的数组要浪费和昂贵得多。

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-inforEach等更有效。

注意2013年8月添加,2015年2月更新:下面的答案来自2009年,与JavaScript的泛型Array类型有关。它与ES2015中定义的较新的类型化数组无关[现在可在许多浏览器中使用],如Int32Array等。还要注意,ES2015为数组添加了fill方法类型化数组,这可能是填充它们的最有效方法…

此外,它可以对创建数组的某些实现产生很大影响。特别是Chrome的V8引擎,如果它认为可以,它会尝试使用高效的连续内存数组,仅在必要时转移到基于对象的数组。


对于大多数语言,它将是预分配,然后是零填充,如下所示:

function newFilledArray(len, val) {var rv = new Array(len);while (--len >= 0) {rv[len] = val;}return rv;}

但是,JavaScript数组不是真正的数组,它们是键/值映射,就像所有其他JavaScript对象一样,所以没有“预分配”要做(设置长度不会分配那么多槽来填充),也没有任何理由相信倒数到零的好处(这只是为了在循环中快速进行比较)不会因为以相反的顺序添加键而被压倒,因为实现可能已经优化了与数组相关的键的处理,理论上你通常会按顺序进行。

事实上,Matthew Crumley指出,在Firefox上倒计时明显比倒计时慢,这是我可以确认的结果——它是数组的一部分(循环到零仍然比循环到var中的限制更快)。显然,在Firefox上以相反的顺序将元素添加到数组是一个缓慢的操作。事实上,结果因JavaScript实现而有所不同(这并不令人惊讶)。这是一个用于浏览器实现的快速而肮脏的测试页面(下图)(非常脏,在测试期间不会屈服,因此提供的反馈很少,并且会违反脚本时间限制)。我建议在测试之间刷新;如果你不这样做,FF(至少)会在重复测试时减慢速度。

相当复杂的版本使用Array#conat比FF上的直接初始化快,大约在1,000到2,000个元素数组之间。然而,在Chrome的V8引擎上,每次…

这里有一个测试:

const tests = [{name:   "downpre",total:  0,desc:   "Count down, pre-decrement",func:   makeWithCountDownPre},{name:   "downpost",total:  0,desc:   "Count down, post-decrement",func:   makeWithCountDownPost},{name:   "up",total:  0,desc:   "Count up (normal)",func:   makeWithCountUp},{name:   "downandup",total:  0,desc:   "Count down (for loop) and up (for filling)",func:   makeWithCountDownArrayUp},{name:   "concat",total:  0,desc:   "Concat",func:   makeWithConcat}];
const q = sel => document.querySelector(sel);
let markup = "";for (const {name, desc} of tests) {markup += `<div><input type="checkbox" id="chk_${name}" checked><label for="chk_${name}">${desc}</label></div>`;}q("#checkboxes").innerHTML = markup;q("#btnTest").addEventListener("click", btnTestClick);
function btnTestClick() {// Clear logq("#log").innerHTML = "Testing...";
// Show runningq("#btnTest").disabled = true;
// Run after a pause while the browser updates displaysetTimeout(btnTestClickPart2, 0);}
function btnTestClickPart2() {try {runTests();} catch (e) {log(`Exception: ${e.message}`);}
// Re-enable the buttonq("#btnTest").disabled = false;}
function getNumField(name) {const val = q("#" + name).value.trim();const num = /^\d+$/.test(val) ? parseInt(val) : NaN;if (isNaN(num) || num <= 0) {throw new Error(`Invalid ${name} value ${JSON.stringify(val)}`);}return num;}
function runTests() {try {// Clear logq("#log").innerHTML = "";
const runCount = getNumField("loops");const length = getNumField("length");
// Do it (we run runCount + 1 times, first time is a warm up)for (let counter = 0; counter <= runCount; ++counter) {for (const test of tests) {if (q("#chk_" + test.name).checked) {const start = Date.now();const a = test.func(length);const time = Date.now() - start;if (counter == 0) {// Don't count (warm up), but do check the algorithm worksconst invalid = validateResult(a, length);if (invalid) {log(`<span class=error>FAILURE</span> with test ${test.name}: ${invalid}`);return;}} else {// Count this onelog(`#${counter}: ${test.desc}: ${time}ms`);test.total += time;}}}}
for (const test of tests) {if (q("#chk_" + test.name).checked) {test.avg = test.total / runCount;if (typeof lowest != "number" || lowest > test.avg) {lowest = test.avg;}}}
let results ="<p>Results:" +"<br>Length: " + length +"<br>Loops: " + runCount +"</p>";for (const test of tests) {if (q("#chk_" + test.name).checked) {results +=`<p ${lowest == test.avg ? " class=winner" : ""}>${test.desc}, average time: ${test.avg}ms</p>`;}}results += "<hr>";q("#log").insertAdjacentHTML("afterbegin", results);} catch (e) {log(e.message);return;}}
function validateResult(a, length) {if (a.length != length) {return "Length is wrong";}for (let n = length - 1; n >= 0; --n) {if (a[n] != 0) {return "Index " + n + " is not zero";}}return undefined;}
function makeWithCountDownPre(len) {const a = new Array(len);while (--len >= 0) {a[len] = 0;}return a;}
function makeWithCountDownPost(len) {const a = new Array(len);while (len-- > 0) {a[len] = 0;}return a;}
function makeWithCountUp(len) {const a = new Array(len);for (let i = 0; i < len; ++i) {a[i] = 0;}return a;}
function makeWithCountDownArrayUp(len) {const a = new Array(len);let i = 0;while (--len >= 0) {a[i++] = 0;}return a;}
function makeWithConcat(len) {if (len == 0) {return [];}let a = [0];let currlen = 1;while (currlen < len) {const rem = len - currlen;if (rem < currlen) {a = a.concat(a.slice(0, rem));} else {a = a.concat(a);}currlen = a.length;}return a;}
function log(msg) {const p = document.createElement("p");p.textContent = msg;q("#log").appendChild(p);}
body {font-family: sans-serif;}#log p {margin: 0;padding: 0;}.error {color: red;}.winner {color: green;}
<div><label for='txtLength'>Length:</label><input type='text' id='length' value='1000'><br><label for='txtLoops'>Loops:</label><input type='text' id='loops' value='100000'><div id='checkboxes'></div><br><input type='button' id='btnTest' value='Test'><hr><div id='log'></div></div>

var str = "0000000...0000";var arr = str.split("");

在表达式中的用法:arr[i]*1;

编辑:如果arr应该用于整数表达式,那么请不要介意'0'的char值。您只需按如下方式使用它:a = a * arr[i](假设a具有整数值)。

我知道我在某个地方有这个原型:)

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 methodArray.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 assignmentArray.prototype.init2 = function(x,n){if(typeof(n)=='undefined') { n = this.length; }while (n--) { this.push(x); }return this;}
//joshua's methodfunction 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=156dB=359dC=125dD=375dE=468dF=412
FF3.5 deltas:dA=6dB=13dC=63dD=8dE=12dF=8

因此,根据我的估计,推送通常确实较慢,但在FF中使用较长的数组时表现更好,但在IE中表现更差,这在一般情况下很糟糕(奇怪)。

我已经测试了IE 6/7/8、Firefox 3.5、Chrome和Opera中预分配/不预分配、向上/向下计数和for/这时循环的所有组合。

下面的函数在Firefox,Chrome和IE8中一直是最快或非常接近的,并且不比Opera和IE6中的最快慢多少。在我看来,它也是最简单和最清晰的。我发现几个浏览器的同时循环版本略快,所以我也包括它以供参考。

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;}

我最快的函数是:

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

使用本机推送和移位将项目添加到数组中比声明数组范围并引用每个项目来设置其值要快得多(大约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 millisecondsst = (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

我很想知道T. J.克劳德对此有什么看法?:-)

这样做的最快方法是使用for每个=)

(我们保持IE<9的向后兼容性)

var fillArray = Array.prototype.forEach? function(arr, n) {arr.forEach(function(_, index) { arr[index] = n; });return arr;}: function(arr, n) {var len = arr.length;arr.length = 0;while(len--) arr.push(n);return arr;};
// testfillArray([1,2,3], 'X'); // => ['X', 'X', 'X']

如果您需要在代码执行期间创建许多不同长度的零填充数组,我发现实现这一目标的最快方法是创建一个零数组一次,使用本主题中提到的方法之一,您知道长度永远不会超过,然后根据需要对该数组进行切片。

例如(使用上面选择的答案中的函数来初始化数组),创建一个长度为最大长度的零填充数组,作为需要零数组的代码可见的变量:

var zero = newFilledArray(maxLength, 0);

现在每次你需要一个长度为必填长度<最大长度的零填充数组时,都对这个数组进行切片:

zero.slice(0, requiredLength);

我在代码执行期间创建了数千次零填充数组,这极大地加快了这个过程。

new Array(51).join('0').split('')怎么样?

function zeroFilledArray(size) {return new Array(size + 1).join('0').split('');}

虽然这是一个旧的线程,但我想添加我的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]

在我对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('');}

我正在测试T. J. 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)调用该方法。

我只是使用:

var arr = [10];for (var i=0; i<=arr.length;arr[i] = i, i++);

您可以检查索引是否存在,以便将+1附加到它。

这样你就不需要一个零填充数组。

示例:

var current_year = new Date().getFullYear();var ages_array = new Array();
for (var i in data) {if(data[i]['BirthDate'] != null && data[i]['BirthDate'] != '0000-00-00'){
var birth = new Date(data[i]['BirthDate']);var birth_year = birth.getFullYear();var age = current_year - birth_year;
if(ages_array[age] == null){ages_array[age] = 1;}else{ages_array[age] += 1;}
}}
console.log(ages_array);

我通常使用Uint8Array的方式(并且速度惊人)。例如,创建一个零填充的1M元素向量:

  var zeroFilled = [].slice.apply(new Uint8Array(1000000))

我是一个Linux的用户,一直为我工作,但是有一次一个使用Mac的朋友有一些非零元素。我以为他的机器出故障了,但这仍然是我们找到的最安全的修复方法:

  var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))

编辑

Chrome

  1. 弗雷德里克·戈特利布-6.43
  2. Sam Barnum-4.83
  3. 伊莱-3.68
  4. 约书亚记2.91
  5. 马修·克拉姆利-2.67
  6. 布杜兰-2.55
  7. 艾伦·赖斯-2.11
  8. kangax-0.68
  9. Tj. Crowder-0.67
  10. ZERTOSH-错误

Firefox 20.0

  1. 艾伦·赖斯-1.85
  2. 约书亚-1.82
  3. 马修·克拉姆利-1.79
  4. 布杜兰-1.37
  5. 弗雷德里克·戈特利布-0.67
  6. Sam Barnum-0.63
  7. 伊莱-0.59
  8. kagax-0.13
  9. Tj. Crowder-0.13
  10. ZERTOSH-错误

错过了最重要的测试(至少对我来说):Node.js。我怀疑它接近Chrome基准。

默认情况下,Uint8ArrayUint16ArrayUint32Array类将零作为其值,因此您不需要任何复杂的填充技术,只需执行以下操作:

var ary = new Uint8Array(10);

默认情况下,数组ary的所有元素都是零。

使用豆沙强调

_.range(0, length - 1, 0);

或者如果您有一个现有的数组并且您想要一个长度相同的数组

array.map(_.constant(0));

ES6引入了Array.prototype.fill。它可以这样使用:

new Array(len).fill(0);

不确定它是否很快,但我喜欢它,因为它简短而自我描述。

它仍然不在IE(检查兼容性)中,但有一个可提供PolyFill

可能值得指出的是,Array.prototype.fill是作为ECMAScript 6(和谐)提案的一部分添加的。在考虑线程中提到的其他选项之前,我宁愿使用下面写的Polyill。

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;};}

在这里找到另一个不错的选择http://www.2ality.com/2013/11/initializing-arrays.html

function fillArrayWithNumbers(n) {var arr = Array.apply(null, Array(n));return arr.map(function (x, i) { return i });}

匿名函数:

(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);// => [0, 0, 0, 0, 0]

使用for-loop稍微短一点:

(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

其他人似乎缺少的是事先设置数组的长度,以便解释器不会不断更改数组的大小。

我的单行代码是Array.prototype.slice.apply(new Uint8Array(length))

但是如果我要创建一个函数来快速完成它,而不需要一些hacky解决方法,我可能会写一个这样的函数:

var filledArray = function(value, l) {var i = 0, a = []; a.length = l;while(i<l) a[i++] = value;return a;}

我不反对:

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);new Array(5+1).join('0').split('').map(parseFloat);

由Zertoph建议,但在新的es6数组扩展中允许您使用fill方法本机执行此操作。现在IE边缘、Chrome和FF支持它,但请检查兼容性表

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]

前面提到的ES 6填充方法很好地解决了这个问题。大多数现代桌面浏览器已经支持今天所需的数组原型方法(Chromium、FF、Edge和Safari)[1]。您可以在MDN上查找详细信息。一个简单的使用示例是

a = new Array(10).fill(0);

鉴于当前的浏览器支持,您应该谨慎使用它,除非您确定您的受众使用现代桌面浏览器。

循环代码的最短

a=i=[];for(;i<100;)a[i++]=0;
edit:for(a=i=[];i<100;)a[i++]=0;orfor(a=[],i=100;i--;)a[i]=0;

安全var版本

var a=[],i=0;for(;i<100;)a[i++]=0;
edit:for(var i=100,a=[];i--;)a[i]=0;

用预计算值填充数组的优雅方法

这里有另一种使用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());}

此方法还可用于通过利用回调中提供的index参数生成数字序列:

> Array.from(Array(10), (d, i) => i)< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

奖励答案:使用Stringrepeat()填充数组

由于这个答案得到了很多关注,我也想展示这个很酷的技巧。虽然不如我的主要答案有用,但将介绍仍然不太为人所知但非常有用的Stringrepeat()方法。这是诀窍:

> "?".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]

return Array( quantity ).fill(1).map( n => return n * Math.abs(~~(Math.random() * (1000 - 1 + 1)) + 1) );

一条线。

如果你使用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]

在答案中没有看到这个方法,所以这里是:

"0".repeat( 200 ).split("").map( parseFloat )

因此,您将获得长度为200的零值数组:

[ 0, 0, 0, 0, ... 0 ]

我不确定这段代码的性能,但如果您将其用于相对较小的数组,这应该不是问题。

ECMAScript2016开始,对于大型数组有一个明确的选择。

由于这个答案仍然显示在谷歌搜索的顶部附近,这里有一个2017年的答案。

这是当前的jsBench,其中包含几十种流行的方法,包括迄今为止就此问题提出的许多方法。如果您发现更好的方法,请添加、分叉和分享。

我想指出的是,没有真正最有效的方法来创建任意长度的零填充数组。您可以优化速度,或者优化清晰度和可运维性-根据项目的需要,任何一种都可以被认为是更有效的选择。

在优化速度时,您希望:使用文字语法创建数组;设置长度,初始化迭代变量,并使用这时循环遍历数组。这是一个例子。

const arr = [];arr.length = 120000;let i = 0;while (i < 120000) {arr[i] = 0;i++;}

另一种可能的实施方式是:

(arr = []).length = n;let i = 0;while (i < n) {arr[i] = 0;i++;}

但是我强烈反对在实践中使用第二次植入,因为它不太清楚,并且不允许您在数组变量上保持块范围。

这些比用for循环填充要快得多,比标准方法快大约90%

const arr = Array(n).fill(0);

但是这种填充方法仍然是较小数组的最有效选择,因为它清晰、简洁和可运维性。除非你制作了大量长度为数千或更多的数组,否则性能差异可能不会杀死你。

其他一些重要的注意事项。大多数样式指南建议您在使用ES6或更高版本时不再使用var,除非有非常特殊的原因。对于不会重新定义的变量使用const,对于会重新定义的变量使用letMDNAirbnb的风格指南是获取有关最佳实践的更多信息的好地方。这些问题与语法无关,但重要的是,JS新手在搜索大量新旧答案时了解这些新标准。

豆沙

_.fill(array, value)

是一种干净且跨浏览器安全的填充数组的方法。

递归解

正如其他一些人所指出的,使用.concat()通常可以提供快速的解决方案。这是一个简单的递归解决方案:

function zeroFill(len, a){return len <= (a || (a = [0])).length ?a.slice(0, len) :zeroFill(len, a.concat(a))}
console.log(zeroFill(5));

和一个通用的递归数组填充函数:

function fill(len, v){return len <= (v = [].concat(v, v)).length ?v.slice(0, len) : fill(len, v)}
console.log(fill(5, 'abc'));

ES6解决方案:

[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]

总之

最快的解决方案:

let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;

最短(方便)的解决方案(小数组慢3倍,大数组稍慢(Firefox上最慢))

Array(n).fill(0)

详情

今天2020.06.09我在浏览器Chrome83.0、Firefox 77.0和Safari13.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)的解决方案对于小阵列来说速度很快
  • 基于fill(B, C)的解决方案在Chrome和Safari上速度很快,但在Firefox上对于大数组来说速度最慢
  • 基于Array.apply(P)的解决方案为大数组抛出错误
    function P(n) {return Array.apply(null, Array(n)).map(Number.prototype.valueOf,0);}
    try {P(1000000);} catch(e) {console.error(e.message);}

在此处输入图片描述

代码和示例

下面的代码介绍了测量中使用的解决方案

function A(n) {return [...new Array(n)].fill(0);}
function B(n) {return new Array(n).fill(0);}
function C(n) {return Array(n).fill(0);}
function D(n) {return Array.from({length: n}, () => 0);}
function E(n) {return [...new Array(n)].map(x => 0);}
// arrays with type
function F(n) {return Array.from(new Int32Array(n));}
function G(n) {return Array.from(new Float32Array(n));}
function H(n) {return Array.from(new Float64Array(n)); // needs 2x more memory than float32}
function I(n) {return new Float32Array(n); // this is not typical array}
function J(n) {return [].slice.apply(new Float32Array(n));}
// Based on for
function K(n) {let a = [];a.length = n;let i = 0;while (i < n) {a[i] = 0;i++;}return a;}
function L(n) {let a=[]; for(let i=0; i<n; i++) a[i]=0;return a;}
function M(n) {let a=[]; for(let i=0; i<n; i++) a.push(0);return a;}
function N(n) {let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;return a;}
function O(n) {let a = new Array(n); for (let i=n; i--;) a[i] = 0;return a;}
// other
function P(n) {return Array.apply(null, Array(n)).map(Number.prototype.valueOf,0);}
function Q(n) {return "0".repeat( n ).split("").map( parseFloat );}
function R(n) {return new Array(n+1).join('0').split('').map(parseFloat)}
// ---------// TEST// ---------[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R].forEach(f => {let a = f(10);console.log(`${f.name} length=${a.length}, arr[0]=${a[0]}, arr[9]=${a[9]}`)});
This snippets only present used codes

Example results for Chrome:

enter image description here

创建一个全新的数组

new Array(arrayLength).fill(0);

在现有数组的末尾添加一些值

[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]

示例

//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);

let filled = [];filled.length = 10;filled.fill(0);
console.log(filled);

const arr = Array.from({ length: 10 }).fill(0);console.log(arr)

这里最快的是

(arr = []).length = len; arr.fill(0);

我知道这不是问这个问题的目的,但是这里有一个开箱即用的想法。为什么?我的 CSci 教授指出,用零来“清理”数据并没有什么神奇之处。所以最有效的方法就是根本不去做!只有在初始条件(如某些求和)中数据需要为零时才这样做——对于大多数应用程序来说通常不是这种情况。

const item = 0
const arr = Array.from({length: 10}, () => item)

const item = 0
const arr = Array.from({length: 42}, () => item)
console.log('arr', arr)

let arr = [...Array(100).fill(0)]

在我的测试目前为止,这是最快的在我的电脑

对于1亿个元素需要大约350毫秒。

"0".repeat(100000000).split('');

对于相同数量的元素,map(()=>0)需要大约7000毫秒,这是一个巨大的差异