# Array and Object
# 1、类数组(打印结果)
var obj1 = {
'6': 6,
'2': 2,
'1': 5,
length: 2,
splice: Array.prototype.splice,
push: Array.prototype.push,
};
obj1.push(-6);
obj1.push(0);
obj1.push(6);
obj1.push(66);
obj1.push(666);
console.log(obj1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 涉及知识点
# 类数组(ArrayLike)
一组数据由数组来存,但是如果对数组进行扩展,会影响到数组的原型,ArrayLike 的出现则提供了一个中间数据桥梁,ArrayLike 有数组的特性,但是对ArrayLike 的扩展不会影响到原数组。
# push 方法
push方法有意具有通用性。改方法和call() 和 apply() 一起使用时,可以应用在类数组对象上。push 方法根据length 属性来决定从哪开始插入给定的值。如果length不能被转成一个数值,则插入的元素索引为0,包括length不存在时,当length不存在时,将会创建它。
唯一的原生类数组(array-like)对象是 String,尽管如此,让门并不适用该方法,因为字符串是不可改变的。
# 对象转数组的方式
Array.from()、splice()、concat() 等。
# 题分析
这个obj中定义了两个key值,分别是splice和push分别对应数组圆形中的splice和push方法,因此这个obj可以调用数组中的splice和push方法。
- 调用对象的push方法,push(-6),
因为此时obj定义的length是2,所以从数组中的第二项开始插入,也就是数组的第三项,因为数组的索引是从0开始,此时定义了2和6的下标,所以会替代第三项也就是下标是2的值,此时key为2的属性值为-6。
- 调用对象的push方法,push(0),
因为此时obj定义的length是3,所以从数组中的第三项开始插入,也就是数组的第四项,因为数组的索引是从0开始,此时定义了2和6的下标,所以会替代第三项也就是下标是3的值,但是此时没有下标是3的值,所以插入下标3,值为0。
- 因为没有定义0这两项,所以前面会是 empty。
结果:
# 2、. 和 连续赋值 优先级
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a, '====', b)
1
2
3
4
2
3
4
# 结果
# 分析
- 首先前两行,a和b同时指向了值为{n: 1}的内存地址(以下简称:RAM1);
- 然后第三句,
- 需要说的前提是:
赋值是从右到左的
,. 的优先级高于 =
; - 所以,此时a.x 中的a内存地址是RAM1,并且此时在RAM1内存的值新增了x属性;
- 后面a={n: 2}优先执行,此时的a执行新的内存地址(RAM2),值为{n: 2};
- 然后执行a.x = a,即a.x= {n: 2},a.x指向新a的内存地址(即:RAM2);
- 此时的b的内存地址依然是RAM1,b不仅拥有第一步a({n: 1})的值,也新增了x属性。
- 需要说的前提是:
# for 和 forEach 哪个效率高
测试代码:
let arr = new Array(arrLength);
console.time('for');
for (let i = 0; i < arrLength; i++) {}
console.timeEnd('for');
console.time('forEach');
arr.forEach((a) => {});
console.timeEnd('forEach');
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
结果:
# 分析
# for
- 需要获取容器的大小,如果你计算大小比较耗时,那么for循环的效率会很低;(这个问题在例子中可以忽略)
- 为了 防止循环越界,每次循环都需要进行一次比较。
# forEach
forEach 编译成字节码之后,使用的是迭代器实现的,所以本质上是通过迭代器遍历的。
public static void testForEach(List list) {
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object t = iterator.next();
Object obj = t;
}
}
1
2
3
4
5
6
2
3
4
5
6
可以看到,只比迭代器遍历多了生成中间变量这一步,因此性能也略微下降了一些。
- 无需获取容器大小。
- 需要创建额外的迭代器变量。
- 遍历期间得到的是对象,没有索引位置信息,因此没办法将指定索引位置对象替换为新对象,也就是不能赋值。