在面试过程中,会遇到有关Symbol的问题,所以学习了下:
<script>
//=======Symbol:
//Symbol是由ES6规范引入的一项新特性,是一种新的基础数据类型,它的功能类似于一种标识唯一性的ID。
//通常情况下,我们可以通过调用Symbol()函数来创建一个Symbol实例,用来表示独一无二的值,是一种原始数据类型。
let x = Symbol();
console.log(typeof x); //symbol
// Symbol函数可以接受字符串为参数,表示对Symbol实例的描述。为在控制台输出,或者转换为字符串时,比较容易区分.
let s2 = Symbol('another symbol')
// ES2019提供了一个属性description,直接返回Symbol的描述
// Symbol值都是不相等的,意味着Symbol值可以作为标识符,用于对象的属性名,就可以保证不会出现同名的属性
let s3 = Symbol('another symbol')
console.log(s3 === s2); //false
// Symbol作为对象的属性名时,不能用点运算符,要使用[]
let a = Symbol();
let obj1 = {
[a]: function (arg) {
console.log(arg)
}
}
obj1[a](123); //123
// Symbol作为属性名时,该属性是公有属性,不是私有属性,
// 使用场景:
// 1、定义一组常量,保证常量的值都不相等.示例1:
const log = {};
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
}
console.log(log.levels.DEBUG, 'debug messagee'); //Symbol(debug) "debug messagee"
console.log(log.levels.INFO, 'info messagee'); //Symbol(info) "info messagee"
// 示例2:
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol();
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_RED;
case COLOR_GREEN:
return COLOR_GREEN;
default:
throw new ERROR('undefined color')
}
}
// 常量使用symbol值最大好处,就是其他任何值都不可能有相同的值,因此可以保证上面的switch语句会按设计的方式工作。
//2、作为对象的key属性,防止对象属性被重写,示例:
let name = Symbol();
{
plugin = {};
plugin[name] = 'plugin';
console.log(plugin[name]); //plugin
}
{
let name = Symbol();
plugin[name] = 'user';
console.log(plugin[name]);//user
}
console.log(plugin); //{Symbol(): "plugin", Symbol(): "user"}
console.log(plugin[name]); //plugin
// 当使用了Symbol作为对象的属性key后,在对该对象进行key的枚举时,会有什么不同?在实际应用中,我们经常会需要使用Object.keys()或者for...in来枚举对象的属性名,那在这方面,Symbol类型的key表现的会有什么不同之处呢?来看以下示例代码:
let object1 = {
[Symbol('name')]: '一斤代码',
age: 18,
title: 'enginner'
}
Object.keys(object1);//["age", "title"]
for (let p in object1) {
console.log(p); //age title
}
Object.getOwnPropertyNames(object1);//["age", "title"]
// 从以上代码的输出,不难看出,Symbol类型的key是不能通过Object.keys()或者for...in来枚举,它未被包含在对象自身的属性名集合(property names)之中。所以,利用该属性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。
// 当使用JSON.stringify(),将对象转换为JSON字符串时,Symbol也被排除在外,即不含Symbol的值。
console.log(JSON.stringify(object1)); //{"age":18,"title":"enginner"}
// 那么,怎么获取以Symbol方式定义的对象属性呢?可以使用下列针对Symbol的API:
// => 使用Object的API:
Object.getOwnPropertySymbols(object1); //[Symbol(name)]
// => 使用新增的反射API
Reflect.ownKeys(object1); //(3) ["age", "title", Symbol(name)]
// 3、使用Symbol定义类的私有属性/方法
// 模块化中的使用,在a.js文件中:
const PASSWORD = Symbol();
class Login {
constructor(username, password) {
this.username = username;
this[PASSWORD] = password;
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login;
// b.js文件:
import Login from './a.js';
const login = new Login('admin', '123455');
login.checkPassword('123456');
login.PASSWORD // oh!no!
login[PASSWORD];// oh!no!
login['PASSWORD']// oh!no!
// 由于Symbol常量被定义在a.js模块中,在b。js中拿不到,也不能创建一个一模一样的(是唯一的),所以这个PASSWORD是限制在a.js中。所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。
// 注册和获取全局Symbol
//通常情况下,在浏览器窗口(window)中,使用Symbol()函数来定义和Symbol实例就够了,但,如果应用设计到多个window(如使用iframe),并需要这些window中创建的Symbol是同一个,就不能使用Symbol()函数了。要使用另一个API:就是Symbol.for()
//可以注册或获取一个window间全局的Symbol实例
let gs1 = Symbol.for('global_symbol_1'); //注册一个全局Symbol
let gs2 = Symbol.for('global_symbol_1');
//获取全局Symbol
console.log(gs1 === gs2); //true
</script>
参考:https://www.jianshu.com/p/f40a77bbd74e