本文内容
- JS 基本数据类型种类
- Symbol 的主要用法, 全局 Symbol 的使用与检测
- Symbol 与其他基本类型转换时的规则
ES6 引入了一种新的原始数据类型,表示独一无二的值,最大的用处是作为对象属性的唯一标识符。
至此,Javascript 拥有 6 种基本数据类型和一种复杂数据类型。
数据类型
基本类型
- string
- number
- boolean
- undefined
- null
- symbol
复杂类型
- object
用法
基本语法
Symbol([description])
- description 可选的描述,一般用在调试的时候作为区分,但是 不能用来访问 Symbol。
- 该方法返回一个 symbol 值
let s = Symbol('test');
let s2 = Symbol('test');
let s3 = new Symbol('test'); // TypeError
console.log(s === s2); // false
console.log(typeof s); // symbol
console.log(s.description); // test
- 每次调用 Symbol()返回的值都是独一无二的,不管描述是否一致。
-
Symbol
不支持new
调用 - 通过 description 属性可以获取到传入 Symbol 的描述性字符串
全局单例的 Symbol
使用 Symbol.for()可以创建全局单例的 symbol 值,语法如下:
Symbol.for([name])
- name 可选的描述,建议传入,否则 name 会作为 undefined 传入
- 类似于单例模式,执行环境 (一般是浏览器) 内部维护了一个全局 Symbol 注册表,记录 name 和 Symbol(name)关系
- 尝试通过 name 在该注册表查找对应 symbol 值,如果找到,则返回这个 symbol 值
- 如果没找到,则使用 Symbol(name)创建一个 symbol 值,并记录该 symbol 值与 name 的关联关系,之后返回该 symbol
const name = Symbol('name');
const name2 = Symbol.for('name');
const name3 = Symbol.for('name');
console.log(name === name2); // false
console.log(name2 === name3); // true
-
全局 Symbol 映射关系中 name 是作为字符串来使用的,结构类似下面的代码:
const globalSymbols = {name: Symbol('name') };
- 使用同样的字符串描述调用 Symbol()和 Symbol.for()获取到的 symbol 值不相等
查找是否为全局的单例 Symbol
使用 Symbol.keyFor()可以检测给定的 symbol 值是否是全局单例的 symbol(简单来说就是检测是否是 Symbol.for()创建的),语法如下:
Symbol.keyFor(symbol)
- symbol 必传,待检测的 symbol 值
- 如果给定的 symbol 值是通过 Symbol.for()得到的,该方法返回传入 symbol 的字符串描述
- 如果给定的 symbol 值不是通过 Symbol.for()得到的,该方法返回 undefined
const s = Symbol('s1');
const s2 = Symbol.for('s2');
console.log(Symbol.keyFor(s)); // undefined
console.log(Symbol.keyFor(s2)); // s2
Symbol 与 JSON.stringify
Symbol 类型的属性不会参与 JSON 的序列化
const name = Symbol('name');
const obj = {[name]: 'xialei',
data: 1
};
console.log(JSON.stringify(obj)); // {"data": 1}
Symbol 与 for … in 和 for … of
Symbol 类型的属性不会出现在 for … in 和 for … of 循环中
const name = Symbol('name');
const user = {[name]: 'xialei',
data: 1
};
for(let i in user) {console.log(i, user[i]);
}
// 上述循环输出 data 1
for(let i of user) {console.log(i, user[i]);
}
// TypeError: user 不是可迭代对象
Symbol 与 Object.keys()和 Object.getOwnPropertyNames()
Symbol 类型的属性不会出现在 Object.keys()和 Object.getOwnPropertyNames()返回结果中
const name = Symbol('name');
const user = {[name]: 'xialei',
data: 1
};
console.log(Object.keys(user)); // ["data"]
console.log(Object.getOwnPropertyNames(user)); // ["data"]
Symbol 与 Object.getOwnPropertySymbols()
Symbol 类型的属性会出现在 Object.Object.getOwnPropertySymbols()
const name = Symbol('name');
const user = {[name]: 'xialei',
data: 1
};
console.log(Object.Object.getOwnPropertySymbols(user)); // [Symbol(name)]
Symbol 数据类型转换
const name = Symbol('1');
console.log(name + 1); // TypeError
console.log(Number(name)); // 创建包装对象
console.log(name + '1'); // TypeError
console.log(String(name)); // Symbol(1)
console.log(!!name); // true
console.log(Boolean(name)); // true
- symbol 值不能转换为数字
- symbol 不能直接转换为字符串,需要通过 String 包装才能转化
- symbol 可以直接转换为 boolean,转化后为 true
结尾
- 使用 Symbol 最大的注意事项应该是使用方括号语法去访问对应的属性,而不是字符串。
- Symbol 数据类型转换规范比较简单,大部分场景下也没用拿 Symbol 去做数据转换