编写代码中通常会有快速初始化数组的需求,例如我们需要一个类似matlab里的zeros函数,假如这里我们需要生成一个0-23的数组用于表示一天24小时。

最基本的做法如下:

function(){
let hours = [];
for(let k = 0; k < 24; k++ )hours.push(k);
return hours;
}

下面我们来思考如何用更优雅的方式实现。

考虑使用new Array(24)+ map的方法来实现。

代码如下:

Array(24).map((_, h) => h);

注意,这里map的第二个参数是索引,平时用的少,这里把索引作为数值。

结果与预期并不符合,为啥呢?

简单搜索了一下,发现时因为js里的稀疏数组的逻辑导致的。

我们先看一下下面的代码:

let a = [];
a[1000] = 2;
console.log(a.length);
// 1000
a.forEach(x => console.log("hello"));
// only one "hello"

js的处理逻辑是,对于没有主动赋值的位置进行“空置”处理,对于这些“空置”未知,迭代器是不会理会的,这么做最主要的目的就是避免不合理的赋值操作导致的bug。

假设没有这种逻辑,我们写下了new Array(Date.now()),这将导致系统新建一个非常大的数组,而实际上啥也没存。

我们可以吧new Array(len)干的事情简单理解为下面的过程:

function(len){
let r = [];
r.length = len;
return r;

这就是为什么对new Array(len)调用map或者forEach的时候跟预期不一致了。

如何解决这一问题呢,除了使用new Array(len)的形式,我们还可以使用new Array(1,2,3)这种写法来初始化数组,但是这么写就没法实现我们编写初始化数组的目的了。

这个时候我们想到了apply,这个函数的第二个参数正好就是一个数组,于是我们写下了下面的代码。

// 借用apply
Array.apply(null, Array(24)).map((_, h) => h);
// [0, 1, ..., 24]

得到了我们希望的结果。这就说明,Array(24)apply中作为参数的时候是被当做24个值对待的,因为这一点就保证了最后得到的数组长度是24。

既然如此,我们当然同样可以使用apply的姊妹函数call

// 借用call
Array.call(null, ...Array(24)).map((_, h) => h);
// [0, 1... 23]

这也更确认了一件事,Array(len)解构会得到len个参数而非一个参数,当然call的使用必须在支持解构操作符的环境中。

在熟悉了callapply的原理后,我们可以进一步写出下面的代码:

// Array本身
Array(...Array(24)).map((_, h) => h);
// [0, 1, ..., 24]

这种形式已经足够优雅了。

另外,在ES6中,Array提供了新方法fill,借用该方法填充那些“空置”位,进而保证后续的操作能顺利进行。

具体代码如下:

// 推荐
Array(24).fill(null).map((_, h) => h);

现在也比较推荐最后一种写法,这种方法也最为直观。

不过需要注意fill方法的使用,应该尽量避免盲目地填充,因为这样会上面提到了js设计“空置”逻辑为了避免的bug。

有兴趣的可以尝试一下下面的代码:

// no-fill
console.time("no-fill");
let t = Array(5e7);
console.timeEnd("no-fill");
// fill
console.time("fill");
let q = Array(5e7).fill(null);
console.timeEnd("fill");
// => no-fill: 0.240ms
// => fill: 3247.921ms

在浏览器中尝试浏览器基本会不响应,没有设置更大的数值为了避免得不到结果。假设一个int占用4个字节的内存,这个fill会占用200M的内存,且需要循环5千万次,这必然会占用大量的CPU和内存,在单线程的js中是绝对不允许的。

javascript快速初始化数组的更多相关文章

  1. JavaScript中的数组创建

    JavaScript中的数组创建 数组是一个包含了对象或原始类型的有序集合.很难想象一个不使用数组的程序会是什么样. 以下是几种操作数组的方式: 初始化数组并设置初始值 通过索引访问数组元素 添加新元 ...

  2. C数组&结构体&联合体快速初始化

    背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元 ...

  3. C89,C99: C数组&结构体&联合体快速初始化

    1. 背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组 ...

  4. javascript中快速求数组的全部元素的相加之和

    js中快速求数组的全部元素的相加之和: var arr = [1,2,3,4,5];var sum = eval(arr.join('+')); console.log(sum); 运行结果: 15

  5. JavaScript权威指南 - 数组

    JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...

  6. javascript中关于数组的一些鄙视题

    一.判断一个数组中是否有相同的元素 /* * 判断数组中是否有相同的元素的代码 */ // 方案一 function isRepeat1(arrs) { if(arrs.length > 0) ...

  7. JavaScript Array(数组)对象

    一,定义数组 数组对象用来在单独的变量名中存储一系列的值. 创建 Array 对象的语法: new Array(); new Array(size); new Array(element0, elem ...

  8. JavaScript学习笔记-数组(1)

    数组是值的有序集合.每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引.JavaScript数组是无类型的:数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类型.数 ...

  9. JavaScript快速入门(四)——JavaScript函数

    函数声明 之前说的三种函数声明中(参见JavaScript快速入门(二)——JavaScript变量),使用Function构造函数的声明方法比较少见,我们暂时不提.function func() { ...

  10. JavaScript中对数组的操作

    原文:JavaScript中对数组的操作 一:数组的使用 1.定义:JavaScript中对数组的定义有两种形式.如: .var arr = [12,3,5,8]; .var arr = new Ar ...

随机推荐

  1. dubbo(一)spring schema拓展技术

    https://blog.csdn.net/java_zldz_xuws/article/details/84648398 在阐述dubbo原理之前,我先介绍一下dubbo与spring怎么糅合在一块 ...

  2. Qt音视频开发01-共享解码线程(耗时一年/性能凶残/至臻完美)

    一.前言 大概在8年前就开始用ffmpeg做视频解码的显示,第一个版本就100行代码左右,功能极其简单,就是开个线程解码视频流转成图片发给主界面绘制.时间过得真快,从当初的一胎到现在二胎都上学了三胎计 ...

  3. EPPlus使用方法---Excel处理我觉得超级好用

    目前只是用到导出Excel功能,导出大规模数据量速度也很快,而且比较容易操作(最起码导出是,暂时没有用到处理已存在的excel功能,有人说NPOI也好用,试了一下,最起码导出这个不如EPPlus    ...

  4. Spring+Vue+ElementUI的前后端分离开发项目中,前端向后端发送请求,后端返回错误:Cannot deserialize instance of `java.util.LinkedHashMap` out of START_ARRAY token

    问题描述: Spring+Vue+ElementUI的前后端分离开发项目中,前端向后端发送请求,后端返回错误:Cannot deserialize instance of `java.util.Lin ...

  5. Solution -「ZJOI 2010」「洛谷 P2570」贪吃的老鼠

    \(\mathscr{Description}\)   Link.   有 \(n\) 块奶酪,每块奶酪出现时段为 \([s_i,t_i]\),体积为 \(V_i\):有 \(m\) 只老鼠要吃奶酪, ...

  6. 揭秘10种主流PLC在ModbusTCP通信中的速度表现!

    大家好!我是付工. 通透!终于把ModbusRTU弄明白了 这样看来,ModbusTCP协议太简单了 太简单了!C#轻松实现Modbus通信 前面给大家介绍了一系列关于Modbus和ModbusTCP ...

  7. 2006. 差的绝对值为 K 的数对数目

    给你一个整数数组 nums 和一个整数 k ,请你返回数对 (i, j) 的数目,满足 i < j 且 |nums[i] - nums[j]| == k . |x| 的值定义为: 如果 x &g ...

  8. 从0到1构建开源 vue-uniapp-template:使用 UniApp + Vue3 + TypeScript 和 VSCoe、CLI 开发跨平台移动端脚手架

    作者主页: 有来技术 开源项目: youlai-mall︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 仓库主页: GitCode︱ Gitee ...

  9. 一个简单的大转盘抽奖程序(附.NetCore Demo源码)

    最近闲下来在做一些demo,现在讲一下做的一个简单的大转盘抽奖demo,前端lottery,layui,后端.net core,sqlsugar,数据库用的mysql 1.前端实现: 前端用的是基于开 ...

  10. Q:Linux查看进程启动服务的精确时间

    输入命令 获取进程号 #1#获取进程号ps -ef|grep java|grep 进程名#2#获取启动时间ps -p 进程号 -o lstart  展示启动时间:星期 月 日 小时:分钟:秒 年 一键 ...