每日后台夜聊0x29
每日后端夜话,与你聊聊后端。
每晚18:00准时推送。
文字总数:4012字,1张图片
预计阅读时间:11 分钟
翻译:疯狂的科技极客
原来的:
创建链表的最佳方法是通过文字形式:
1const arr = [0,0,0];
但这不是一个长期的解决方案,例如当我们需要创建小田地时。 这篇博文解释了在这些情况下该怎么做。
没有洞的场地通常表现更好
在大多数编程语言中,链表是连续的值序列。 在 JavaScript 中,数组是将索引映射到元素的字典。 它可以有孔[参见:#sec_array-holes] - 零和字段厚度之间的索引不映射到元素(“缺失索引”)。 例如,下面的数组在索引 1 处有一个洞:
1> Object.keys(['a',, 'c'])
2[ '0', '2' ]
没有空洞的链表称为密集链表或打包链表。 密集链表通常表现更好,因为它们可以连续存储(内部)。 一旦出现漏洞,内部表示就必须改变。 我们有两个选择:
无论哪种情况,如果引擎遇到漏洞,它都不能只是返回 undefinedhtml5数组,它必须遍历原型链并搜索名为“漏洞索引”的属性,这需要更多时间。
在某些引擎中,例如V8,如果切换到性能较低的数据结构,这些更改将是永久性的。 虽然所有的洞都被填满了,但它们不会变回去。
关于V8如何表示链表,请参考Mathias Bynens的文章《V8中的Element Types》[]。
创建链接列表
`数组` 构造函数
如果你想创建一个给定宽度的Array,通常的方法是使用Array构造函数:
1const LEN = 3;
2const arr = new Array(LEN);
3assert.equal(arr.length, LEN);
4// arr only has holes in it
5assert.deepEqual(Object.keys(arr), []);
这些技术很方便,但有两个缺点:
在“Array”构造函数前面添加“.fill()”方法
.fill() 方法将修改当前数组并用指定值填充它。 这有助于在使用 newArray() 创建链表后初始化链表:
1const LEN = 3;
2const arr = new Array(LEN).fill(0);
3assert.deepEqual(arr, [0, 0, 0]);
警告:如果您使用对象作为参数 .fill() 一个链表,所有元素仍将引用同一个实例(即该对象不会被克隆多次):
1const LEN = 3;
2const obj = {};
3
4const arr = new Array(LEN).fill(obj);
5assert.deepEqual(arr, [{}, {}, {}]);
6
7obj.prop = true;
8assert.deepEqual(arr,
9 [ {prop:true}, {prop:true}, {prop:true} ]);
稍后我们将遇到的填充方法(Array.from())不存在这个问题。
`.push()` 方法
1const LEN = 3;
2const arr = [];
3for (let i=0; i < LEN; i++) {
4 arr.push(0);
5}
6assert.deepEqual(arr, [0, 0, 0]);
这次,我们创建并填充了一个没有泄漏的链表。 因此,操作该字段应该比使用构造函数创建它更快。 但创建链表的速度相对较慢,因为随着字段数量的减少,引擎可能需要多次重新分配连续显存。
使用“未定义”填充字段
Array.from() 将可迭代和类似字段的值转换为数组html5数组,将空洞视为未定义的元素。 这可用于将每个孔转换为未定义:
1> Array.from({length: 3})
2[ undefined, undefined, undefined ]
参数 {length: 3} 是一个宽度为 3 的类数组对象,仅包含孔。 您还可以使用 newArray(3),但这通常会创建更大的对象。
以下方法仅适用于可迭代值,但与 Array.from() 具有类似的效果:
1> [...new Array(3)]
2[ undefined, undefined, undefined ]
但是 Array.from() 通过 newArray() 创建其结果,所以你得到的仍然是一个稀疏字段。
使用 Array.from() 进行映射
Array.from() 可用于映射,前提是提供映射函数作为其第二个参数。
用值填充字段
1> Array.from({length: 3}, () => 0)
2 [ 0, 0, 0 ]
1> Array.from({length: 3}, () => ({}))
2[ {}, {}, {} ]
从一系列值创建
1> Array.from({length: 3}, (x, i) => i)
2[ 0, 1, 2 ]
1 > const START=2, END=5;
2 > Array.from({length: END-START}, (x, i) => i+START)
3 [ 2, 3, 4 ]
创建反转整数字段的另一种方法是使用 .keys(),它也将孔视为未定义元素:
1> [...new Array(3).keys()]
2[ 0, 1, 2 ]
.keys() 返回一个可迭代序列。 我们展开它并将其转换为链表。
快速提醒:创建链接列表
填充空白或未定义:
填写任意值:
用整数范围填充:
推荐图案
我更喜欢下面的方式。 我的优点和缺点是可读性,而不是性能。
如果您正在处理整数或浮点数字段,请考虑 TypedArrays - 它就是为此目的而设计的。 它们不能有洞并且总是零初始化的[]。
提示:通常字段的性能并不重要
谢谢