本文详细解析ES6引入的Symbol、Set和Map三大核心特性。Symbol用于生成唯一标识符,解决属性名冲突;Set实现无重复元素集合,支持高效去重与遍历;Map提供键值对存储,支持任意类型键名。掌握这些数据结构可提升代码健壮性与开发效率。
本文介绍ES6中Symbol、Set和Map的具体用法,供读者参考学习。
Symbol:唯一标识符
Symbol
1.Symbol是ES6新增的原始数据类型,代表独一无二的值。它是JavaScript的第七种数据类型,前六种分别为undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)和对象(Object)。
2.Symbol值通过Symbol函数生成,可用作对象的属性名,确保不会与其他属性名发生冲突。
let s = Symbol();
typeof s // symbol
注意:Symbol函数前不能使用new命令,否则报错。因为Symbol是原始类型的值而非对象,所以不能为其添加属性。
3.Symbol函数可接受一个字符串参数,用于描述Symbol实例,主要作用是区分不同的Symbol变量。
let s1 = Symbol('a');
let s2 = Symbol('b');
s1.toString() // 'Symbol(a)'
s2.toString() // 'Symbol(b)'
注意:Symbol函数的参数仅表示对当前Symbol值的描述,因此相同参数的Symbol函数返回值并不相等。
let s1 = Symbol('a');
let s2 = Symbol('a');
s1 === s2 //false
4.Symbol值不能与其他类型的值进行运算,但可以转换为布尔值,无法转换为数值。
let s = Symbol();
s + '2' // Cannot convert a Symbol value to a string
Boolean(s) // true
!s // false
5.用作对象属性名时,Symbol可保证不出现同名属性,非常适合由多个模块构成的对象,防止某个键被意外改写或覆盖。需注意,Symbol值作为属性名时不能使用点运算符,因为点运算符后接的是字符串。
let s = Symbol();
let obj = {};
obj[s] = 'hello world';
//或者
let obj = {
[s] : 'hello world'
}
obj.s // undefined
obj[s] // hello world
6.作为属性名的Symbol不会被常规方法遍历得到,即不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但它并非私有属性,可通过Object.getOwnPropertySymbols方法获取指定对象的所有Symbol属性名。
var obj = {};
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
obj.c = 'Mine';
for( let key in obj ){
console.log(key) // c
}
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
7.Symbol.for方法接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值;它与Symbol()不同的是,Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值,而 Symbol()每次都会返回3不同的Symbol值;
Symbol.for("name") === Symbol.for("name")
// true
Symbol("name") === Symbol("name")
// false
8.Symbol.keyFor方法返回已登记的Symbol类型值的key,而Symbol()写法没有登记机制。
var s1 = Symbol.for("name");
Symbol.keyFor(s1) // "name"
var s2 = Symbol("name");
Symbol.keyFor(s2) // undefined
注意:Symbol.for为Symbol值登记的名字属于全局环境,可在不同的iframe或service worker中获取到同一个值。
Set:无重复元素集合
Set 和 Map
1.ES6提供了新的数据结构Set。它类似于数组,但成员值唯一,无重复值。Set本身是一个构造函数,用于生成Set数据结构。
let s = new Set([1,2,3,4,5,2,2,3,5]);
s // [1,2,3,4,5]
2.可使用add(key)方法向Set中添加元素,重复添加无效。需注意,向Set加入值时不会发生类型转换,即5和"5"是两个不同的值,但在Set内部,两个NaN被视为相等。
let s = new Set([1,2,3]);
s.add(4) //[1,2,3,4]
s.add(4) //[1,2,3,4]
s.add(5) //[1,2,3,4,5]
s.add('5') //[1,2,3,4,5,"5"]
s.add(NaN) //[1,2,3,4,5,"5",NaN]
s.add(NaN) //[1,2,3,4,5,"5",NaN]
3.可利用Set数据不重复的特性,提供一种新的数组去重方法。
// 去除数组的重复成员
[...new Set(array)]
[...new Set([1,2,2,3,3,4,5,5])] //[1,2,3,4,5]
4.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
5.Set结构的实例有四个遍历方法,可用于遍历成员。
keys():返回键名的遍历器 values():返回键值的遍历器 entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员 需特别注意,Set的遍历顺序即为插入顺序。此特性有时非常有用,例如使用Set保存回调函数列表,调用时即可保证按添加顺序执行。
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"]
Map:键值对存储
6.ES6提供了Map数据结构,类似对象,也是键值对的集合,但“键”的范围不限于字符串,各种类型的值(包括对象)均可作为键,是一种更完善的Hash结构实现。若需“键值对”数据结构,Map比Object更合适。
7.Map常见的操作方法包括:
set(key,val):添加某个值,返回Map结构本身。 get(key):读取某个键,若该键未知,则返回undefined delete(key):删除某个键,返回布尔值表示删除是否成功。 has(key):返回布尔值,表示该值是否为Map的键。 clear():清除所有成员,无返回值。
const m = new Map();
const o = { str : 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
8.仅当对同一个对象的引用时,Map结构才将其视为同一个键。
const map = new Map();
const k1 = ['a'];
const k2 = ['a'];
map.set(k1, 111).set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
上述示例表明,Map的键实际上与内存地址绑定,只要内存地址不同,即视为两个键。因k1和k2是两个不同的对象,存放在不同内存地址中,故Map视为不同的键。
9.Map结构原生提供三个遍历器生成函数和一个遍历方法。
keys():返回键名的遍历器。 values():返回键值的遍历器。 entries():返回所有成员的遍历器。 forEach():遍历Map的所有成员。
注意:Map的遍历顺序即为插入顺序,此处不再举例,读者可自行实践。
10.可使用扩展运算符(...)将Map转换为数组;反之,将数组传入Map构造函数,即可转为Map。
//Map转数组
const map = new Map();
map.set('name' , 'hello').set({},'world');
[...map] //[["name","hello"],[{},"world"]]
//数组转Map
const map = new Map([["name","hello"],[{},"world"]]);
map // {"name" => "hello", Object {} => "world"}
感兴趣的朋友可使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。
更多关于JavaScript相关内容可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。