ES6从入门到精通——Symbol、Map 与 Set

Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

基本用法

Symbol 值通过Symbol函数生成,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。

let s1 = Symbol();
let s2 = Symbol();

s1 // Symbol()
s2 // Symbol()

在生成 Symbol 值的时候,可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)

description

创建 Symbol 的时候,可以添加一个描述。如果我们想要得到这个描述,我们可以通过 description 属性直接得到 Symbol 的描述。

const sym = Symbol('foo');

sym.description // "foo"

属性名 Symbol

由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!'
};

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"

在使用过程中需要注意的是,当Symbol 值作为对象属性名时,不能用点运算符,点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值。

let syObject = {};
syObject[sy] = "kk";
 
syObject[sy];  // "kk"
syObject.sy;   // undefined

Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。但是不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。

let syObject = {};
syObject[sy] = "kk";
console.log(syObject);
 
for (let i in syObject) {
  console.log(i);
}    // 无输出
 
Object.keys(syObject);  // []

如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols()Reflect.ownKeys()取到。Object.getOwnPropertySymbols()方法可以获取对象所有 Symbol 属性名。Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

Object.getOwnPropertySymbols(syObject);    // [Symbol(key1)]
Reflect.ownKeys(syObject);                 // [Symbol(key1)]

Symbol.for(),Symbol.keyFor()

Symbol.for()Symbol()这两种写法,都会生成新的 Symbol。而它们的区别,前者可以重新使用已经生成的 Symbol 值。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。

Symbol.for("bar") === Symbol.for("bar")
// true

Symbol("bar") === Symbol("bar")
// false

Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

Map对象

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map对象和object对象之间的区别:

  • 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
  • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
  • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

在创建 Map对象的时候,可以使用无参构造创建,也可以传入一个数组作为参数,会自动将数组转化为Map 对象格式的数据。

const m = new Map();
const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数。SetMap都可以用来生成新的 Map

属性和操作方法

  • size属性返回 Map 结构的成员总数。
  • set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。set方法返回的是当前的Map对象,因此可以采用链式写法。
  • get方法读取key对应的键值,如果找不到key,返回undefined
  • has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
  • delete方法删除某个键,返回true。如果删除失败,返回false。
  • clear方法清除所有成员,没有返回值。
const map = new Map();
map.set('foo', a);
map.set('bar', b).set('bar', c);

map.size // 2
map.get('bar') //c
map.has('bar'); //true
map.delete('bar');//true
map.has('bar'); //false
map.clear('bar');
map.has('bar'); //false

遍历方法

  • Map.prototype.keys():返回键名的遍历器。
  • Map.prototype.values():返回键值的遍历器。
  • Map.prototype.entries():返回所有成员的遍历器。
  • Map.prototype.forEach():遍历 Map 的所有成员。
const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);

for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.values()) {
  console.log(value);
}
// "no"
// "yes"

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

// 等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

Map 与数组互换互相转换

const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])
// Map {
//   true => 7,
//   Object {foo: 3} => ['abc']
// }

Set对象

Set对象类似于数组,但是成员的值都是唯一的,没有重复的值,可以存储任何类型的唯一值,无论是原始值或者是对象引用。

在生成 Set 对象时,可以传入一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化

//无参构造
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4

//有参构造
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

属性和方法

  • size属性返回 Set 实例的成员总数。
  • add(value)添加某个值,返回 Set 结构本身。
  • delete(value)删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value)返回一个布尔值,表示该值是否为Set的成员。
  • clear()清除所有成员,没有返回值。
s.add(1).add(2).add(2);
// 注意2被加入了两次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false

遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9

也可以使用 for…of 循环遍历 Set

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值