Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值。它是JavaScript中的第七种数据类型,与undefined、null、Number(数值)、String(字符串)、Boolean(布尔值)、Object(对象)并列。
你可以这样创建一个Symbol值:
const a = Symbol(); console.log(a); //Symbol()
使用Symbol函数可以生成一个Symbol类型的值,但是你不能在调用Symbol时使用new关键字,因为Symbol是基本数据类型,而不是对象。比如下面的写法是错误的:
//报错,Symbol is not a constructor const a = new Symbol();
使用Symbol()创建一个Symbol类型的值并赋值给a变量后,你就得到了一个在内存中独一无二的值。现在除了通过变量a,任何人在任何作用域内都无法重新创建出这个值。例如当你这样写:
const b = Symbol();
尽管a和b都是使用Symbol()创建出来的,但是它们在内存中看起来却是这样的:
实际上,a变量拿到了内存中某块内存的唯一引用(这里所说的引用,其实就是该内存的地址)。如果不借助a变量,你不可能再得到这个地址。因此:
a !== b; //a和b持有的是两块内存的引用 const c = a; //手动把a里保存的地址保存在c变量中 a === c; //c和a现在指向同一块内存,因为它们保存了同样的地址
这种行为看似难以理解,但其实它与对象遵循相同的规则,如:
var a = {}; var b = {}; a !== b; //a和b各自被分配了不同的内存,因此它们保存了不同的地址 //借助变量a,变量c拿到了a指向的那个对象的地址,因此两者相等 var c = a; a === c;
但是对于同为基本数据类型的字符串来说,它不遵循类似的规则。
比如:
var a = "123"; var b = "123"; a === b; //返回true。两者在常量区引用同一个字符串
我们首先通过变量a在内存中创建了字符串“123”,然后在不借助变量a的情况下,又通过var b = "123"拿到了对“123”这个字符串的引用,两者指向内存中的同一块内存地址。
因此我们说,a无法确保别的变量无法拿到它保存的地址(前提是不通过a)。但是对于var a = Symbol()这样的语句,a变量内保存的值是唯一的,因为除了借助a变量,你永远无法得到a中保存的值。这也是Symbol的本质。
可能很多人比较奇怪,一个Symbol类型的变量里面到底保存了什么呢?
我们看两行代码:
var a = Symbol(); console.log(a); //Symbol()
我们试图输出a的值,但js引擎输出了Symbol()。显然它不能说明a的值是字符串,因为:
typeof a === "symbol";
所以说如果你想问js引擎a的值是多少,引擎只会告诉你它是一个Symbol类型的值。也就是说,Symbol真正存储了什么并不重要,重要的是它的值永远不会与别的值相等。Symbol的中文释义为“标志,符号”,一个Symbol类型的变量只是为了标记一块唯一的内存而存在的。也正是因为这样,Symbol类型的值不参与运算。