ECMAScript 6(六)

Symbol & Set 和 Map 数据结构

Posted by     "Jordon Li" on Monday, December 23, 2019

TOC

ECMAScript 6 简介

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

Symbol

原始数据类型Symbol

  • 基本用法: ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull布尔值(Boolean)字符串(String)数值(Number)对象(Object)Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,
    • 一种是原来就有的字符串,
    • 另一种就是新增的 Symbol 类型。 凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。
    //Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
    let s1 = Symbol('foo');
    let s2 = Symbol('bar');
    
    s1 // Symbol(foo)
    s2 // Symbol(bar)
    
    s1.toString() // "Symbol(foo)"
    s2.toString() // "Symbol(bar)"
    

Symbol.prototype.description

  • 基本用法: ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。
    const sym = Symbol('foo');
    sym.description // "foo"
    

作为属性名的 Symbol

  • 基本用法: 由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
    let mySymbol = Symbol();
    
    // 第一种写法
    let a = {};
    a[mySymbol] = 'Hello!';
    
    // 第二种写法
    let a = {
      [mySymbol]: 'Hello!'
    };
    
    // 第三种写法
    let a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    
    // 以上写法都得到同样结果
    a[mySymbol] // "Hello!"
    

Symbol.for(),Symbol.keyFor()

  • 基本用法:
    • Symbol.for(): 有时,我们希望重新使用同一个 Symbol 值,Symbol.for()方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
    • Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key
    //Symbol.for()
    let s1 = Symbol.for('foo');
    let s2 = Symbol.for('foo');
    s1 === s2 // true
    
    //Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。
    //它们的区别是,前者会被登记在全局环境中供搜索,后者不会
    Symbol.for("bar") === Symbol.for("bar") // true
    Symbol("bar") === Symbol("bar") // false
    
    //Symbol.keyFor()
    let s1 = Symbol.for("foo");
    Symbol.keyFor(s1) // "foo"
    
    let s2 = Symbol("foo");
    Symbol.keyFor(s2) // undefined
    

内置的 Symbol 值

  • 基本用法:
    • Symbol.hasInstance:对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。
    • Symbol.isConcatSpreadable:对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
    • Symbol.species:对象的Symbol.species属性,指向一个构造函数。创建衍生对象时,会使用该属性。
    • Symbol.match:对象的Symbol.match属性,指向一个函数。当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
    • Symbol.replace:对象的Symbol.replace属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值。
    • Symbol.search: 对象的Symbol.search属性,指向一个方法,当该对象被String.prototype.search方法调用时,会返回该方法的返回值。
    • Symbol.split: 对象的Symbol.split属性,指向一个方法,当该对象被String.prototype.split方法调用时,会返回该方法的返回值。
    • Symbol.iterator: 对象的Symbol.iterator属性,指向该对象的默认遍历器方法。
    • Symbol.toPrimitive: 对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
    • Symbol.toStringTag: 对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。
    • Symbol.unscopables: 对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除。

Set 和 Map 数据结构

Set

  • 基本用法: ES6 提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
// 例一
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

// 例二
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
items.size // 5
  • Set 实例的属性:
    • Set.prototype.constructor:构造函数,默认就是Set函数。
    • Set.prototype.size:返回Set实例的成员总数。
  • Set 实例的方法:
    • Set.prototype.add(value):添加某个值,返回 Set 结构本身。
    • Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    • Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
    • Set.prototype.clear():清除所有成员,没有返回值。
  • 遍历操作:
    • Set.prototype.keys():返回键名的遍历器
    • Set.prototype.values():返回键值的遍历器
    • Set.prototype.entries():返回键值对的遍历器
    • Set.prototype.forEach():使用回调函数遍历每个成员

WeakSet

  • 基本用法: WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别:
    • WeakSet 的成员只能是对象,而不能是其他类型的值。
    • WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用。 也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

Map

  • 基本用法: ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);
  • Map 实例的属性:
    • Map.prototype.constructor:构造函数,默认就是Map函数。
    • Map.prototype.size:返回Map实例的成员总数。
  • Map 实例的方法:
    • Map.prototype.set(key, value)set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
    • Map.prototype.get(key)get方法读取key对应的键值,如果找不到key,返回undefined
    • Map.prototype.has(key)has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
    • Map.prototype.delete(key)delete方法删除某个键,返回true。如果删除失败,返回false
    • Map.prototype.clear()clear方法清除所有成员,没有返回值。。
  • 遍历操作:
    • Map.prototype.keys():返回键名的遍历器
    • Map.prototype.values():返回键值的遍历器
    • Map.prototype.entries():返回所有成员的遍历器
    • Map.prototype.forEach():遍历 Map 的所有成员

WeakMap

  • 基本用法: WeakMap结构与Map结构类似,也是用于生成键值对的集合。WeakMapMap的区别有两点:
    • WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
    • WeakMap的键名所指向的对象,不计入垃圾回收机制。

「下次一定」

下次一定

使用微信扫描二维码完成支付