新的 JavaScript“符号”数据类型都有哪些可能的使用场景?

Posted

技术标签:

【中文标题】新的 JavaScript“符号”数据类型都有哪些可能的使用场景?【英文标题】:What are the possible usage scenarios for the new JavaScript "Symbol" datatype?新的 JavaScript“符号”数据类型有哪些可能的使用场景? 【发布时间】:2015-01-26 04:11:34 【问题描述】:

我刚刚偶然发现了 javascript 中新的(针对 ES6 提出,但已经在 Firefox、Chrome 和 Opera 中实现)数据类型的文档,Symbol

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol http://people.mozilla.org/~jorendorff/es6-draft.html#sec-symbol-objects

我正在阅读它,但我想不出可能的使用场景。

文档说:

符号是唯一且不可变的数据类型,可用作对象属性的标识符。

好的,好吧,假设我按照文档所说的那样做:

obj[Symbol("a")] = "a";

但是,由于 Symbol('a') 总是返回唯一值(对象)并且:

符号在 for...in 迭代中不可见。

如何从 obj 检索我的财产?

var obj =  normalProperty: 'just a string' ;
obj[Symbol('a')] = 'a';

document.getElementById('retrieve').addEventListener('click', function() 
  document.write('Stringified object:' + JSON.stringify(obj) + '<br/><br/>');
  document.write('Trying to get Symbol-property value, aaaand...: <br/>');
  document.write(obj[Symbol('a')]); // undefined
, false);
&lt;button id="retrieve"&gt;Retrieve obj's property&lt;/button&gt;

编辑

当然,你可以这样检索它:

var x = Symbol('a');
obj[x] = 'a';
obj[x]; // "a"

但是这样做的目的是什么?

提前致谢:)

【问题讨论】:

也许是经典的封装用例? 相关帖子 - What is the “symbol” primitive data type in JavaScript, What is the point of the 'Symbol' type in ECMA-262-v6? & What is the motivation for bringing Symbols to ES6? What is the motivation for bringing Symbols to ES6?的可能重复 【参考方案1】:

在阅读了文档并在 chrome 中使用了这个 Symbol 类型之后,似乎 Symbol 是一种定义名称的方式——而不是值——,事实上,使用定义的属性使用 for..inObject.getOwnPropertyNames()JSON.stringify() 使符号不可见,使符号对元数据属性有用:

// define metadata symbols
var Metadata = 
        Date: Symbol('Message date')
;

var email = function(recipient, message) 
    this.Recipient = recipient;
    this.Message = message;
    this[Metadata.Date] = new Date();
;

var email1 = new email('@Me', 'test');
JSON.stringify(email1);
// 
//    Recipient: '@Me',
//    Message: 'test'
// 

// Date is still accessible using
email1[Metadata.Date];
// Thu Nov 27 2014 16:50:00 GMT+0000

// Debugging in Console:
// 
//    Recipient: '@Me',
//    Message: 'test'
//    Symbol(Message date): Thu Nov 27 2014 16:50:00 GMT+0000
// 

可以使用Symbol.for 函数将符号设为全局,因此元数据名称可以创建一次并在所有项目文件中使用。

使用符号访问值需要在创建时引用该符号。即使使用相同的描述,每次调用 Symbol() 都会创建一个新的:

var a = Symbol('a');
var b = Symbol('a');
a != b
// and
a != Symbol('a')

但是,使用Symbol.for创建一个符号,它将被注册到一个全局注册表中并且描述成为一个键,意味着全局注册表中只有一个具有相同键的符号:

var a = Symbol.for('a');
var b = Symbol.for('a');
a == b
// and
a == Symbol.for('a')

【讨论】:

【参考方案2】:

它们几乎可以帮助我们解决命名冲突。每当您想以独特的方式创建属性时,就应该使用符号。

看看我的例子

const bert = Symbol('Bert');

'伯特'

注意:这不是一个值,这是他们所谓的描述符, 因为符号本身只是一个唯一标识符。所以如果你是 想象一个符号可能是什么,也许你可以想象是 像这样的“sdfasdfa2342134987fgsdfgsdf9808fsfgsd”绝对 唯一的符号,这样您就可以确保它永远不会覆盖 那里的任何其他代码。

这很酷的是,如果我创建第二个符号,例如

const person = Symbol('Bert')

你可以看到我再次使用了“Bert”。因为我将它们描述为相同的东西,所以它们会相同吗?

const bert = Symbol('Bert');
const person = Symbol('Bert');


console.log(bert);
console.log(person);
console.log(bert === person);
console.log(bert == person);

如果您正在创建类的对象,这可能很有用。

  const classRoom = 
    'Mia' :  grade: 50, gender: 'female' ,
    'Gilbert':  grade: 80, gender: 'male' ,
    'Gilbert'  grade: 80, gender: 'male' ,
  ;

但是你有另一个名字叫 Gilbert,所以你有一个命名冲突。所以想象一下,如果你正在处理数以百万计的数据。因此,我们可以使用符号来命名,而不是使用人名或使用某种唯一标识符。

  const classRoom = 
    [Symbol('Mia')] :  grade: 50, gender: 'female' ,
    [Symbol('Gilbert')]:  grade: 80, gender: 'male' ,
    [Symbol('Gilbert')]:  grade: 80, gender: 'male' ,
  ;

关于符号的另一件事是它们不可枚举,这意味着如果我要这样做,我们就无法循环它们

  for (const person in classRoom) 
    console.log(person);
  

我什么也得不到。

如果您确实想要访问所有符号,因为它们是您想要获取的一些信息,您可以使用对象方法。

  const syms = Object.getOwnPropertySymbols(classRoom);
  const data = syms.map(sym => classRoom[sym]);
  console.log(data);

【讨论】:

以上是关于新的 JavaScript“符号”数据类型都有哪些可能的使用场景?的主要内容,如果未能解决你的问题,请参考以下文章

javascript的引用数据类型都有哪些

js常用的数据类型都有哪些

C语言变量的基本类型都有哪些?

java中都有哪些类?

数据库中逻辑运算符都有哪些

python的数据类型都有哪些