JavaScript ECMAScript 6中Symbol的用途是什么?

10
Symbol是ECMAScript6中的一种新类型,它是一种基本数据类型,主要用于创建唯一的标识符。Symbol的值是只读且不能改变的,每个Symbol都是唯一的。在JavaScript中,对象属性和方法名可以使用Symbol作为标识符,这样可以避免命名冲突。
下面的示例返回false,因为使用Symbol('foo')创建的两个Symbol值虽然具有相同的名称,但它们是不同的,所以使用“===”比较时返回false。

2
MDN文档非常清晰明了:“从Symbol()返回的每个符号值都是唯一的。” - rmlan
@Bergi 哈哈,发现得好,我现在完全不知道我在这里回答什么并收集数据以回答这个问题,而没有注意到它已经被回答了。那个问题可能应该有一个更易找到的标题(编辑了那个问题的标题)。 - nicael
@nicael,你仍然可以在这里删除你的(好!)答案,并将其重新发布到那里以获得更大的受众。 - Bergi
@Bergi 已完成,感谢您的建议。 - nicael
3个回答

14

Symbol用于创建完全独特的、独一无二的标识符。它的使用恰好就是你列出的那个例子。

即使您使用相同的字符串调用Symbol,实例也会不同。这使得可以使用不同的库(可能同时使用)定义可以同时使用的键。

例如,想象两个库使用通用名称来在windowglobal上定义某些内容(或者为了说明,是虚拟全局变量door):

const door = {};
// from library 1
door.cake = () => console.log('chocolate');
// from library 2
door.cake = () => console.log('vanilla');

// your code
door.cake();

在这个例子中,第一个库的代码被遗失了,因为它无意中被赋予了与第一个相同的名称。
现在,如果它们都使用Symbol,即使它们被命名为相同的名称,您仍然可以访问它们(假设它们某种方式导出了Symbol):

const door = {};
// library 1
const cake1 = Symbol('cake');
door[cake1] = () => console.log('chocolate');
// library 2
const cake2 = Symbol('cake');
door[cake2] = () => console.log('vanilla');
// your code
door[cake1]();
door[cake2]();

两者仍然可以访问。

这有点过于简化,但它阐明了要点。

在更实际的用法中,它们用于诸如导入模块之类的事情。模块可能会以相同的名称结束,但没关系,因为它们将具有与其关联的唯一符号,只要您拥有Symbol对象,它们就是独一无二的可访问的。

至于何时自己使用它们...这可能会相当罕见。您主要想在任何时候提供Symbol但需要其他内容保持唯一时使用它们。我只在少数情况下直接使用过这些内容,其中创建的元素可能相同。

例如,如果您正在使用名称作为键来制作对象,则可能会有重复的名称。没有符号,对象将彼此覆盖。有了符号,它们都将保持不变。

const people = {};
people[Symbol('bob')] = { name: 'Bob Smith' };
people[Symbol('bob')] = { name: 'Bob Jones' };


我曾尝试在https://dev59.com/9rjoa4cB1Zd3GeqPCqwV上提问,但被告知这是重复的。使您的代码运行的唯一事情是`cake1`和`cake2`具有不同的名称,但这些名称是由开发人员分配的。在这种情况下,`Symbol`如何帮助解决问题?如果将`cake1`和`cake2`重命名为`cake`,则会出现错误,因为它们**不是唯一的**。如果`Symbol`旨在缓解唯一性问题,则似乎在这里并没有起到帮助作用。 - Andy
1
你把要用作键的值和变量名混淆了。如果你使用let或const,就不能在同一作用域内重新声明相同的变量名(也不应该这样做)。这与Symbol无关。Symbol是为了确保每次调用Symbol时,无论如何都会得到一个完全独特的标识符。我设置的“相同”东西是Symbol('cake'),以展示即使我创建了两个具有相同名称(或“描述”,参数可能被称为)的符号,它也会生成两个唯一的Symbols。当你将它们用作对象中的键时,它们指的是两个不同的东西。 - samanime

7

来自文档

Symbol()返回的每个符号值都是唯一的。

这意味着使用 === 比较将失败,因为它们不是相同的。

如果您想要某种唯一标识符,可以给它一个描述性的名称(如果其他方面没有关系),那么Symbol可能会有用。


好的,但是在JavaScript中什么时候需要使用Symbol呢? - Mohamed Ben HEnda
这可以用于需要唯一标识符(如UUID),但不关心实现细节或内容的情况。 - tadman

2

Symbol的思想是将私有属性引入Javascript。但是,它的实际目的是为了防止名称冲突。

然而不幸的是,它们最终被严重降级,并不是真正的私有属性,因为你可以通过反射找到它们,具体来说,是通过Object.getOwnPropertySymbols方法和代理。

由Symbol()返回的每个符号值都是唯一的。符号值可用作对象属性的标识符;这是该数据类型的唯一目的。(根据mozilla)

var Pet = (function() {
  var typeSymbol = Symbol('type');
  function Pet(type) {
    this[typeSymbol] = type;
  }
  Pet.prototype.getType = function(){
    return this[typeSymbol];
  }
  return Pet;
}());

var a = new Pet('dog');
console.log(a.getType()); // prints dog
a[Object.getOwnPropertySymbols(a)[0]] = "cat"
console.log(a.getType()); //prints cat

这是一个可能的用例,尽管我不认为它是主要推动力。更多的是为了处理不同的代码来源相互覆盖的情况。 - samanime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接