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


当前回答

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

常量项=0constarr=Array.from({length:42},()=>项)控制台日志('arr',arr)

其他回答

新的Array(51).join(“0”).split(“”)怎么样?

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通常比in、forEach等更有效。

其他人似乎缺少的是预先设置数组的长度,这样解释器就不会不断改变数组的大小。

我的简单一行代码是Array.protocol.slice.apply(newUint8Array(长度))

但是,如果我要创建一个函数来快速执行,而不需要一些复杂的变通方法,我可能会编写一个这样的函数:

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

我只使用:

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

2013年8月添加的注释,2015年2月更新:以下2009年的答案与JavaScript的通用数组类型有关。它与ES2015中定义的较新类型数组(现在在许多浏览器中都可用)无关,如Int32Array等。还要注意,ES2015为数组和类型化数组都添加了填充方法,这可能是填充它们的最有效方法。。。

此外,它可以对某些实现的创建数组的方式产生很大的影响。特别是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#concat的相当复杂的版本比FF上的直接初始化快,大约在1000到2000个元素数组之间。不过,在Chrome的V8引擎上,每次都是直接初始化获胜。。。

这里有一个测试:

常量测试=[{name:“倾盆大雨”,总计:0,desc:“倒计数,预减量”,函数:makeWithCountDownPre},{name:“downpost”,总计:0,desc:“倒数,递减后”,函数:makeWithCountDownPost},{name:“up”,总计:0,desc:“向上计数(正常)”,func:makeWithCountUp},{name:“向下和向上”,总计:0,desc:“向下计数(循环)和向上计数(填充)”,func:makeWithCountDownArrayUp},{name:“concat”,总计:0,desc:“凹形”,函数:makeWithConcat}];const q=sel=>document.querySelector(sel);let markup=“”;for(测试的常量{name,desc}){标记+=`<div><input type=“checkbox”id=“chk_${name}”checked><label for=“chk_${name}”>${desc}</label></div>`;}q(“#checkbox”).innerHTML=标记;q(“#btnTest”).addEventListener(“单击”,btnTestClick);函数btnTestClick(){//清除日志q(“#log”).innerHTML=“测试…”;//显示正在运行q(“#btnTest”).disabled=true;//在浏览器更新显示时暂停后运行setTimeout(btnTestClickPart2,0);}函数btnTestClickPart2(){尝试{运行测试();}捕获(e){日志(`异常:${e.message}`);}//重新启用按钮q(“#btnTest”).disabled=false;}函数getNumField(名称){const val=q(“#”+名称).value.trim();常量num=/^\d+$/.test(val)?parseInt(val):NaN;如果(isNaN(num)||num<=0){抛出新错误(`无效的${name}值${JSON.stringify(val)}`);}返回num;}函数runTests(){尝试{//清除日志q(“#log”).innerHTML=“”;const runCount=getNumField(“loops”);const length=getNumField(“长度”);//做它(我们运行runCount+1次,第一次是热身)for(让counter=0;counter<=runCount;++counter){for(测试的常量测试){如果(q(“#chk_”+测试名称)已选中){const start=Date.now();const a=测试函数(长度);const time=Date.now()-开始;如果(计数器==0){//不要计算(预热),但要检查算法是否有效常量无效=validateResult(a,长度);if(无效){日志(`<span class=error>FAILURE</span>,测试${test.name}:${invalid}`);回来}}其他{//数数这个日志(“#${counter}:${test.desc}:${time}毫秒”);test.total+=时间;}}}}for(测试的常量测试){如果(q(“#chk_”+测试名称)已选中){test.avg=测试总数/运行计数;if(typeof lowest!=“number”||最低>测试.avg){最低=测试平均值;}}}let结果=“<p>结果:”+“<br>长度:”+长度+“<br>循环:”+runCount+“</p>”;for(测试的常量测试){如果(q(“#chk_”+测试名称)已选中){结果+=`<p${最低==test.avg?“class=winner”:“”}>${test.desc},平均时间:${test.avg}毫秒</p>`;}}结果+=“<hr>”;q(“#log”).insertAdjacentHTML(“afterbegin”,结果);}捕获(e){日志(e.message);回来}}函数validateResult(a,长度){如果(a.length!=长度){return“长度错误”;}for(设n=长度-1;n>=0;--n){如果(a[n]!=0){return“索引”+n+“不为零”;}}返回未定义;}函数makeWithCountDownPre(len){const a=新数组(len);而(--len>=0){a[len]=0;}返回a;}函数makeWithCountDownPost(len){const a=新数组(len);而(len-->0){a[len]=0;}返回a;}函数makeWithCountUp(len){const a=新数组(len);for(设i=0;i<len;++i){a[i]=0;}返回a;}函数makeWithCountDownArrayUp(len){const a=新数组(len);设i=0;而(--len>=0){a[i++]=0;}返回a;}函数makeWithConcat(len){如果(长度==0){返回[];}设a=[0];设currlen=1;while(currlen<len){常量rem=长度-电流;如果(rem<currlen){a=a.oncat(a.slice(0,rem));}其他{a=混凝土(a);}currlen=a.length;}返回a;}函数日志(msg){const p=document.createElement(“p”);p.text内容=消息;q(“#log”).appendChild(p);}正文{字体系列:无衬线;}#对数p{边距:0;填充:0;}.错误{颜色:红色;}.获胜者{颜色:绿色;}<div><label for='textLength'>长度:</label><input type='text'id='Length'value='1000'><br><label for='xtLoops'>循环:</label><input type='text'id='Loops'value='100000'><div id='checkboxs'></div><br><input-type='button'id='btnTest'value='Test'><小时><div id='log'></div></div>