第 06 章 集合引用类型
Object
- new 操作符和 Object 构造函数
- 对象字面量(object literal)表示法
Array
创建数组
- 使用 Array 构造函数
let colors = new Array(20); // 初始 length 为 20 的数组 let colors = new Array("red", "blue", "green"); // 创建一个包含 3 个字符串值的 数组
- 数组字面量(array literal)表示法
Array.from()
的第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个 length 属性和可索引元素的结构。console.log(Array.from("Matt")); // ["M", "a", "t", "t"]
Array.of()
可以把一组参数转换为数组。console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] console.log(Array.of(undefined)); // [undefined] console.log(Array.of()) // []
数组空位
使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ES6 新增方法普遍将这些空位当成存在的元素,只不过值为 undefined,ES6 之前的方法则会忽略这个空位,但具体的行为也会因方法而异。 由于行为不一致和存在性能隐患,因此实践中要避免使用数组空位。如果确实需要 空位,则可以显式地用 undefined 值代替。
数组索引
数组 length 属性的独特之处在于,它不是只读的。通过修改 length 属性,可以从数组末尾删除或添加元素。来看下面的例子:
检测数组
if (value instanceof Array) {
// 操作数组
}
使用 instanceof
的问题是假定只有一个全局执行上下文。如果网页里有多个框架,则可能涉及两 个不同的全局执行上下文,因此就会有两个不同版本的 Array 构造函数。为解决这个问题,ECMAScript 提供了 Array.isArray()
方法。
if (Array.isArray(value)) {
// 操作数组
}
迭代器方法
在 ES6 中,Array 的原型上暴露了 3 个用于检索数组内容的方法:keys()
、values()
和 entries()
复制和填充方法
使用 fill()
方法可以向一个已有的数组中插入全部或部分相同的值。开始索引用于指定开始填充 的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。负值索引从数组末尾开始计算。 也可以将负索引想象成数组长度加上它得到的一个正索引。fill()
静默忽略超出数组边界、零长度及方向相反的索引范围
fill(7, 1, 3);// 用7填充索引大于等于1且小于3的元素
copyWithin()
会按照指定范围浅复制数组中的部分内容,然后将它们插入到指定索引开始的位置。开始索引和结束索引则与 fill()
使用同样的计算方法
// 把数组从target开始 复制[start,end]的内容
arr.copyWithin(target, start = 0, end = arr.length)
let ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
ints.copyWithin(5); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
转换方法
valueOf()
返回的还是数组本身。而 toString()
返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串。toLocaleString
会调用数组每个值的 toLocaleString()
方法
栈方法
- push
- pop
队列方法
- shift()
- push()
- unshift()
排序方法
sort()
操作方法
-
concat()
打平数组参数的行为可以重写,方法是在参数数组上指定一个特殊的符号:
Symbol.isConcatSpreadable
。这个符号能够阻止concat()
打平参数数组。相反,把这个值设置为 true 可以强制打平类数组对象 -
slice()
-
splice()
搜索和位置方法
ECMAScript 提供了 3 个严格相等的搜索方法:indexOf()
、lastIndexOf()
和 includes()
。
ECMAScript 也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数。断言函数的返回 值决定了相应索引的元素是否被认为匹配。断言函数接收 3 个参数:元素、索引和数组本身。
find()
和 findIndex()
方法使用了断言函数。
迭代方法
- every()
- filter()
- forEach()
- map()
- some()
归并方法
reduce()
和 reduceRight()
Map
const m = new Map();
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
const m2 = new Map({
[Symbol.iterator]: function*() {
yield ["key1", "val1"];
yield ["key2", "val2"];
yield ["key3", "val3"];
}
});
const m3 = new Map([[]]); // Map(1) {undefined => undefined}
Map 可以使用任何 JavaScript 数据类型作为键
Map 内部使用 SameValueZero 比较操作
SameValue (Object.is()) 和严格相等(===)相比,对于NaN和+-0 的处理不同
Object.is(NaN, NaN) // true
Object.is(0, -0) // false
SameValueZero 与 SameValue 的区别主要在于 0 与 -0 是否相等。includes
内部使用的比较算法就是 SameValueZero
const s = new Set()
s.add(0)
s.add(NaN)
s.has(-0) // true
s.has(NaN) // true
与 Object 类型的一个主要差异是,Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。
entries() 扩展操作
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]]
Map or Object
- 内存占用
不同浏览器的情况不同,但给定固定大小的内存,Map 大约可以比 Object 多存储 50%的键/值对。 - 插入性能
Map略快 - 查找速度
性能差异极小,但如果只包含少量键/值对, 则 Object 有时候速度更快。 - 删除性能
对大多数浏览器引擎来说,Map 的 delete()操作都比插入和查找更快。
WeakMap
ECMAScript 6 新增的“弱映射”(WeakMap),弱映射中的键只能是 Object 或者继承自 Object 的类型。
const wm = new WeakMap();
const key1 = {id: 1},
key2 = {id: 2},
key3 = {id: 3};
// 使用嵌套数组初始化弱映射
const wm1 = new WeakMap([
[key1, "val1"],
[key2, "val2"],
[key3, "val3"]
]);
alert(wm1.get(key1)); // val1
// 初始化是全有或全无的操作
// 只要有一个键无效就会抛出错误,导致整个初始化失败
const wm2 = new WeakMap([
[key1, "val1"], ["BADKEY", "val2"], [key3, "val3"]
]);
// TypeError: Invalid value used as WeakMap key
typeof wm2;
// ReferenceError: wm2 is not defined
// 原始值可以先包装成对象再用作键
const stringKey = new String("key1"); const wm3 = new WeakMap([
stringKey, "val1"
]);
alert(wm3.get(stringKey)); // "val1"
弱映射的键是弱键,这些键不属于正式的引用,不会阻止垃圾回收。值不是弱引用,只要键存在,值不会被回收。
const wm = new WeakMap();
wm.set(new Array(1234567), "val"); // WeakMap {Array(1234567) => "val"}
// ---- 垃圾回收 Chrome 里点击Memory里面的小垃圾桶
wm // WeakMap {}
使用弱映射
1、私有变量
私有变量会存储在弱映射中,以对象实例为键,以私有成员的字典为值。
const User = (() => {
const wm = new WeakMap();
class User {
constructor(id) {
this.idProperty = Symbol('id');
this.setId(id);
}
setPrivate(property, value) {
const privateMembers = wm.get(this) || {};
privateMembers[property] = value;
wm.set(this, privateMembers);
}
getPrivate(property) {
return wm.get(this)[property];
}
setId(id) {
this.setPrivate(this.idProperty, id);
}
getId(id) {
return this.getPrivate(this.idProperty);
}
}
return User;
})();
const user = new User(123);
alert(user.getId()); // 123
user.setId(456);
alert(user.getId()); // 456
这样外部无法访问 user 内部的 wm 。且当 user 没有被引用时,不会因为 vm 的引用影响垃圾回收。
2、DOM节点元数据
const wm = new WeakMap();
const loginButton = document.querySelector('#login');
// 给这个节点关联一些元数据
wm.set(loginButton, {disabled: true});
当节点从 DOM 树中被删除后,垃圾回收程序就 可以立即释放其内存(假设没有其他地方引用这个对象)
Set
const m = new Set();
const s1 = new Set(["val1", "val2", "val3"]);
const s2 = new Set({
[Symbol.iterator]: function*() {
yield "val1";
yield "val2";
yield "val3";
}
});
alert(s2.size); // 3
// has add delete size
Set 会维护值插入时的顺序,因此支持按顺序迭代。
const s = new Set(["val1", "val2", "val3"]);
alert(s.values === s[Symbol.iterator]); // true
alert(s.values === s.keys); // true
for (let value of s.values()) {
alert(value);
}
// val1
// val2
// val3
for (let value of s[Symbol.iterator]()) {
alert(value);
}
// val1
// val2
// val3
console.log([...s]); // ["val1", "val2", "val3"]
for (let pair of s.entries()) {
console.log(pair);
}
// ["val1", "val1"]
// ["val2", "val2"]
// ["val3", "val3"]
s.forEach((val, dupVal) => alert(`${val} -> ${dupVal}`));
// val1 -> val1
// val2 -> val2
// val3 -> val3
WeakSet
弱集合中的值只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置值会抛出 TypeError。
因为 WeakSet 中的值任何时候都可能被销毁,所以没必要提供迭代其值的能力。没有 clear()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!