上接语言基础:JavaScript高级程序设计基础(十)
五、集合引用类型
5.1 object
此处简单介绍object,object由两种方式可以创造:由构造函数new Object(),或者对象字面量。如果想要修改对象的值可以用点语法,如object.name="123",如果属性名含有可能会导致语法错误的字符,可以使用中括号,如object["my name"]="123"。
5.2 Array
5.2.1 创建数组
Array 构造函数还有两个ES6新增的用于创建数组的静态方法:from()和of()。from()用于将类数组结构转换为数组实例,而of()用于将一组参数转换为数组实例。
javascript
// 字符串会被拆分为单字符数组
console.log(Array.from("Matt")); // ["M", "a", "t", "t"]
// 可以使用from()将集合和映射转换为一个新数组
const m = new Map().set(1, 2)
.set(3, 4);
const s = new Set().add(1)
.add(2)
.add(3)
.add(4);
console.log(Array.from(m)); // [[1, 2], [3, 4]]
console.log(Array.from(s)); // [1, 2, 3, 4]
// Array.from()对现有数组执行浅复制
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1);
console.log(a1); // [1, 2, 3, 4]
alert(a1 === a2); // false
// arguments 对象可以被轻松地转换为数组
function getArgsArray() {
return Array.from(arguments);
}
console.log(getArgsArray(1, 2, 3, 4)); // [1, 2, 3, 4]
Array.from()还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,还可以接收第三个可选参数,用于指定映射函 数中this的值。但这个重写的this值在箭头函数中不适用
javascript
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1, x => x**2);
const a3 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2});
console.log(a2); // [1, 4, 9, 16]
console.log(a3); // [1, 4, 9, 16]
Array.of()可以把一组参数转换为数组
javascript
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
console.log(Array.of(undefined)); // [undefined]
5.2.2 数组空位
使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole),ES6新增方法普遍将这些空位当成存在的元素,只不过值为undefined:
javascript
const options = [1,,,,5];
for (const option of options) {
console.log(option === undefined);
}
// false
// true
// true
// true
// false
由于行为不一致和存在性能隐患,因此实践中要避免使用数组空位。如果确实需要空位,则可以显式地用undefined值代替。
5.2.3 数组索引
数组length 属性的独特之处在于,它不是只读的。通过修改length属性,可以从数组末尾删除或添加元素
javascript
let colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组
colors.length = 2;
alert(colors[2]); // undefined
colors.length = 4;
alert(colors[3]); // undefined
位置3在数组中不存在,因此访问其值会返回特殊值undefined。
5.2.4 检测数组
一个经典的ECMAScript问题是判断一个对象是不是数组。在只有一个网页(因而只有一个全局作用域)的情况下,使用instanceof操作符就足矣:
javascript
if (value instanceof Array){
// 操作数组
}
使用instanceof 的问题是假定只有一个全局执行上下文。如果网页里有多个框架,则可能涉及两个不同的全局执行上下文,那么构造函数就会有差别。为解决这个问题,ECMAScript提供了Array.isArray()方法。
javascript
if (Array.isArray(value)){
// 操作数组
}
5.2.5 迭代器方法
keys()返回数组索引的迭代器,values()返回数组元素的迭代器,而 entries()返回索引/值对的迭代器
javascript
const a = ["foo", "bar", "baz", "qux"];
// 因为这些方法都返回迭代器,所以可以将它们的内容
// 通过Array.from()直接转换为数组实例
const aKeys = Array.from(a.keys());
const aValues = Array.from(a.values());
const aEntries = Array.from(a.entries());
console.log(aKeys); // [0, 1, 2, 3]
console.log(aValues); // ["foo", "bar", "baz", "qux"]
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
使用ES6的解构可以非常容易地在循环中拆分键/值对:
javascript
const a = ["foo", "bar", "baz", "qux"];
for (const [idx, element] of a.entries()) {
alert(idx);
alert(element);
}
// 0
// foo
// 1
// bar
// 2
// baz
// 3
// qux
5.2.6 复制和填充方法
fill()方法可以向一个已有的数组中插入全部或部分相同的值
javascript
const zeroes = [0, 0, 0, 0, 0];
// 用5 填充整个数组
zeroes.fill(5);
console.log(zeroes); // [5, 5, 5, 5, 5]
zeroes.fill(0); // 重置
// 用6 填充索引大于等于3的元素
zeroes.fill(6, 3);
console.log(zeroes); // [0, 0, 0, 6, 6]
zeroes.fill(0); // 重置
// 用7 填充索引大于等于1且小于3的元素
zeroes.fill(7, 1, 3);
console.log(zeroes); // [0, 7, 7, 0, 0];
zeroes.fill(0); // 重置
copyWithin()会按照指定范围浅复制数组中的部分内容,然后将它们插入到指定索引开始的位置
javascript
// 从ints 中复制索引0开始的内容,插入到索引5开始的位置
// 在源索引或目标索引到达数组边界时停止
ints.copyWithin(5);
console.log(ints); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
reset();
// 从ints 中复制索引5开始的内容,插入到索引0开始的位置
ints.copyWithin(0, 5);
console.log(ints); // [5, 6, 7, 8, 9, 5, 6, 7, 8, 9]
reset();
// 从ints 中复制索引0开始到索引3结束的内容
// 插入到索引4开始的位置
ints.copyWithin(4, 0, 3);
alert(ints); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
reset();
5.2.7 转换方法
如果数组中某一项是null或undefined,则在join()、toLocaleString()、 toString()和 valueOf()返回的结果中会以空字符串表示。