目录
基本概念
1. 创建方法
-
符号是原始值,直接用 Symbol() 函数创建
-
因为是原始类型,所以用 typeof 判断数据类型
let sym = Symbol();
console.log(typeof sym); // symbol
-
不能用 new 关键字是为了避免创建符号包装对象。其实像 Boolean String Number 也是原始数据类型,但它们可以用 new 关键字
let myBoolean = new Boolean();
console.log(typeof myBoolean); // object
let myString = new String();
console.log(typeof myString); // object
let myNumber = new Number();
console.log(typeof myNumber); // object
2. 特性
- 实例唯一且不可变,可以接收一个可选参数,方便代码阅读和后期调试,即便参数值一样,两个 symbol 变量也是不一样的
let sym1 = Symbol();
let sym2 = Symbol();
console.log(sym1 == sym2); // false
let sym3 = Symbol('foo');
let sym4 = Symbol('foo');
console.log(sym3 == sym4); // false
- Symbol.for() 创建共享 Symbol , 如果已存在,直接返回已有的 Symbol
let sym1 = Symbol.for('foo');
let sym2 = Symbol.for('foo'); // 已经有同样标记为 'foo' 的 Symbol ,返回 sym1 给 sym2,实现共享
console.log(sym1 == sym2); // true
// 但是混用是不生效的
let sym3 = Symbol('foo');
let sym4 = Symbol.for('foo');
console.log(sym3 == sym4); // false 因为 sym3 并不共享
具体用法
1. 避免产生属性冲突
- 由于 Symbol 的唯一性,所以可以用来确保对象属性使用唯一标识符,避免产生属性冲突的危险。
// 给对象添加 Symbol 类型的属性
let level1 = Symbol('level');
let level2 = Symbol('level'); // level1 和 level2 变量都是表示 参数为 level 的 Symbol 变量
const student = {
name: 'mike',
age: 15,
[level1]: '优秀',
[level2]: '富有' // 即便二者都为 参数为 level 的 Symbol 变量,但是由于 Symbol 的唯一性,所以不会尝试属性冲突
}
console.log(student); // { name: 'mike', age: 15, [Symbol(level)]: '优秀', [Symbol(level)]: '富有' }
// 同时上面的代码可以直接简写为
const student = {
name: 'mike',
age: 15,
[Symbol('level')]: '优秀',
[Symbol('level')]: '富有' // 即便二者都为 参数为 level 的 Symbol 变量,但是由于 Symbol 的唯一性,所以不会尝试属性冲突
}
console.log(student); // { name: 'mike', age: 15, [Symbol(level)]: '优秀', [Symbol(level)]: '富有' }
2. for..in 遍历时会隐藏
像对于一些不想要让他人知道的信息可以用 Symbol ,这样在 for...in 遍历中不会显现出来
例如上面例子中对于学生等级的划分
const student = {
name: 'mike',
age: 15,
[Symbol('level')]: '优秀',
[Symbol('level')]: '富有'
}
for(let pro in student) {
console.log(pro);
}
// name
// age
- 同时 Object.keys() ,Object.getOwnPropertyNames() 也都无法显示 Symbol 类型的属性名
const student = {
name: 'mike',
age: 15,
[Symbol('level')]: '优秀',
[Symbol('level')]: '富有'
}
console.log(Object.keys(student)); // [ 'name', 'age' ]
console.log(Object.getOwnPropertyNames(student)); // [ 'name', 'age' ]
- 不能用 for... of 遍历,会报错,因为 student 是一个对象,没有 Symbol.iterator 属性,for...of 遍历的是有迭代器的
3. Symbol 的获取
- 通过 Object.getOwnPropertySymbols() 能获取到对象中 Symbol 类型的属性,返回值是一个数组。
const student = {
name: 'mike',
age: 15,
[Symbol('level')]: '优秀',
[Symbol('level')]: '富有'
}
let symList = Object.getOwnPropertySymbols(student);
for(let i of symList) {
console.log(i);
}
// Symbol(level)
// Symbol(level)
// 通过访问属性可以获取属性值
for(let i of symList) {
console.log(student[i]);
}
// 优秀
// 富有
4. for...of 遍历
- 如果对象有 Symbol.iterator 属性 就可以被 for...of 遍历
- for...of 遍历前就是判断对象是否有 Symbol.iterator 属性
const student = {
name: 'mike',
age: 15,
[Symbol('level')]: '优秀',
[Symbol('level')]: '富有'
}
const list = [1,2,3,4,5];
console.log(student[Symbol.iterator]); // undefined
console.log(list[Symbol.iterator]); // [Function: values]
// student 用 for...of 遍历会报错
// list 不会报错