✍JavaScript 原始数据类型 Symbol 有什么用?
ES6 引入了新的基本数据类型Symbol和BigInt。今天我们就来了解下Symbol类型。Symbol类型是为了解决命名冲突的问题,顺带还具备模拟私有属性的功能。
创建symbol变量最简单的方法是用Symbol() 函数。sysmbol变量有两点比较特别:
- 作为对象属性名。只有字符串和 symbol 类型才能用作对象属性名。
- 没有两个symbol 的值是相等的。
注意:Symbol 不会被自动转换为字符串
JavaScript 中的大多数值都支持字符串的隐式转换。例如,我们可以alert任何值,都可以生效。Symbol 比较特殊,它不会被自动转换。
例如,这个alert将会提示出错:
let id = Symbol("id"); alert(id); // 类型错误:无法将 Symbol 值转换为字符串。
这是一种防止混乱的“语言保护”,因为字符串和 Symbol 有本质上的不同,不应该意外地将它们转换成另一个。
如果我们真的想显示一个 Symbol,我们需要在它上面调用 .toString(), 如下所示:
const symbol1 = Symbol();
根据规范,对象的属性键只能是字符串类型或者 Symbol 类型。不是 Number,也不是 Boolean,只有字符串或 Symbol 这两种类型。
命名冲突:
例如常见的类,存在潜在缺陷,加入给该类构造函数传入带有iterator迭代器 属性的对象:
const obj = new MyClass({ iterator: 'not a function' });
这时候你在obj上for/of,js就会抛出错误:TypeError: obj is not iterable异常,所以传入对象iterator覆盖了类的iterator,而使用symbol则可以让对象的内部数据和用户数据进水不犯河水,由于symbol无法在JSON里面显示,所以不用担心被传入不合适的Symbol.iterator,确保内置属性和用户属性不会冲突。
私有属性:
由于任何两个symbol都是不相等的,在 JavaScript 里可以很方便地用来模拟私有属性。symbol不会出现在Object.keys()的结果中,因此除非你明确地export一个symbol,或者Object.getOwnPropertySymbols()函数获取,否则其他代码无法访问这个属性。
还有一个原因:是symbol不会出现在JSON.stringify() 的结果里,确切地说是JSON.stringify()会忽略symbol属性名和属性值
用途:
用 Symbol 表示对象内部状态,可以很好地隔离用户数据和程序状态。有了它,我们就不再需要某些命名约定了,比如内部属性用'$'开头。下次碰到需要定义私有属性的时候,试试Symbol类型吧!
私有属性:面向对象编程(OOP)中非常常见的一个特性,一般是指能被class内部的不同方法访问,但不能在类外部被访问,大多数语言都是通过public、private、protected 这些访问修饰符来实现访问控制的。