427

UPDATE: Recently a brilliant article from Mozilla came up. Read it if you're curious.

As you may know they are planning to include new Symbol primitive type in ECMAScript 6 (not to mention some other crazy stuff). I always thought that the :symbol notion in Ruby is needless; we could easily use plain strings instead, like we do in JavaScript. And now they decide to complicate things in JS with that.

I don't understand the motivation. Could someone explain to me whether we really need symbols in JavaScript?

starball
  • 20,030
  • 7
  • 43
  • 238
Yanis
  • 4,847
  • 2
  • 17
  • 17
  • 7
    I don't know how authentic this explanation is, but it's a start: http://tc39wiki.calculist.org/es6/symbols/. – Felix Kling Feb 12 '14 at 09:59
  • 11
    Symbols enable _so much_ , they allow scoped unique identifiers on objects. For example, having properties on objects that are only accessible in one place. – Benjamin Gruenbaum Feb 16 '14 at 01:13
  • 8
    Not sure about that since you can use Object.getOwnPropertySymbols(o) – Yanis Feb 17 '14 at 10:25
  • 7
    It's more uniqueness rather than privacy. – Qantas 94 Heavy Feb 19 '14 at 06:44
  • 2
    They were going to have a more complicated class implementation with `private` and `public` class attribute keywords that they decided to ditch for a simpler class implementation. Instead of `this.x = x` you were supposed to do `public x = x` and for private variables `private y = y`. They decided to ditch that for a much more minimal class implementation. Symbol would then be a required workaround to get private properties in the minimal implementation. – lyschoening Apr 16 '14 at 14:45
  • 1
    Symbols are super useful as sentinel values. For example, if you are piping multiple files to a transform stream, use something like `Symbol("eof")` to represent the end of a file and the beginning of the next. Without Symbols, you need to resort to some form of encoding or use a kludge-y object instance to represent the same thing. – Rich Remer Mar 28 '17 at 01:10
  • 2
    @Yanis Can `enum Response { No = 0, Yes = 1}` be better with `enum Response { No = Symbol(), Yes = Symbol()}`? Read [this](http://2ality.com/2014/12/es6-symbols.html#using-symbols-to-represent-concepts). – overexchange May 12 '18 at 17:34
  • I'd like to stretch that using Symbols for monkey-patching makes it harmless now – theFreedomBanana Aug 30 '19 at 12:12

8 Answers8

262

The original motivation for introducing symbols to Javascript was to enable private properties.

Unfortunately, they ended up being severely downgraded. They are no longer private, since you can find them via reflection, for example, using Object.getOwnPropertySymbols or proxies.

They are now known as unique symbols and their only intended use is to avoid name clashes between properties. For example, ECMAScript itself can now introduce extension hooks via certain methods that you can put on objects (e.g. to define their iteration protocol) without risking them to clash with user names.

Whether that is strong enough a motivation to add symbols to the language is debatable.

Andreas Rossberg
  • 34,518
  • 3
  • 61
  • 72
  • 105
    Most languages (all mainstream ones afaik) provide some mechanism, usually reflection, to get access to private anyway. – Esailija May 14 '14 at 10:58
  • 20
    @Esailija, I don't think that's true -- in particular, since many languages don't offer reflection in the first place. Leaking private state through reflection (like e.g. in Java) should be considered a bug, not a feature. This is especially true on web pages, where having reliable private state can be security-relevant. Currently, the only way to achieve it in JS is through closures, which can be both tedious and costly. – Andreas Rossberg May 14 '14 at 14:37
  • 46
    The mechanism doesn't have to be reflection - C++, Java, C#, Ruby, Python, PHP, Objective-C all allow access one way or another if one really wants to. It's not really about ability but communication. – Esailija May 14 '14 at 15:48
  • 5
    @plalx, on the web, encapsulation sometimes is about security, too. – Andreas Rossberg Mar 01 '15 at 18:27
  • @plalx, the closure environment of a function cannot be inspected, which is the basis e.g. of the module pattern, some class patterns, and similar function-based work-arounds. – Andreas Rossberg Mar 01 '15 at 20:43
  • 1
    @Esailija C++ does not. –  Mar 17 '15 at 09:17
  • There could be non-reflectable private `Symbol` properties too (unfortunately this does not work right now as intended): Use `var obj = {}; var value = something; var key = Symbol(); Object.defineProperty(obj, key, { enumerable: false, value: value });` – Roland Pihlakas May 02 '15 at 16:44
  • Well, one could hook the `Object.getOwnPropertySymbols` function (in the few cases where it is possible) and exclude any "hidden" symbols from the result. Then the true privacy works. And iteration is covered too, by the `enumerable: false` part in my above comment. – Roland Pihlakas May 02 '15 at 16:53
  • 5
    @RolandPihlakas, unfortunately, `Object.getOwnPropertySymbols` is not the only leak; the more difficult one is the ability to use proxies to intercept access to a "private" property. – Andreas Rossberg May 02 '15 at 17:27
  • @AndreasRossberg It looks like I can set and get properties without being intercepted by `Proxy`'s `get` and `set` traps via using `Object.defineProperty` and `Object.getOwnPropertyDescriptor` methods. Does this behavior match the language design? If so, then now the question is, how do I detect the presence of a `Proxy`, so I know to employ these safe methods instead of fast ones? – Roland Pihlakas May 02 '15 at 18:23
  • 1
    @RolandPihlakas, that will likewise just invoke a proxy's `defineProperty` and `getOwnPropertyDescriptor` traps. Also, there intentionally is no way to detect a proxy. – Andreas Rossberg May 02 '15 at 23:56
  • @AndreasRossberg So the only way I see is then to hook `Proxy` constructors (both `new` (using `Proxy`itself) and function forms, plus the `revocable` one) and then to hook the `get`, `set`, `defineProperty` and `getOwnPropertyDescriptor` traps? And optionally, for other unspecified curious purposes which would require detecting the presence of a proxy, the solution is inside that constructor hook to additionally assign some certain non-enumerable symbol to the returned proxy object, while symbol's `get` and `getOwnPropertyDescriptor` accesses would also be hidden by the above trap hooks? – Roland Pihlakas May 03 '15 at 08:44
  • @RolandPihlakas, there are more traps that take or return property names, you'd need to wrap all of them. But even then there might be other leaks (e.g. creating a new realm with a fresh Proxy object). Monkey-patching around this is a horrible idea anyway. And FWIW, you should not try to make proxies detectable -- it is intentional in the design that a proxy can virtualise any regular object, a property you'd break by making proxies distinguishable. – Andreas Rossberg May 03 '15 at 10:54
  • 3
    @AndreasRossberg are there security concerns to `Object.getOwnPropertySymbols()`? I thought the main point of privacy is just to prevent developers from stepping on each others' toes, not make it absolutely impossible for anything (let alone a debugger) to tweak private values – Andy Jun 02 '15 at 02:05
  • @Andy, if privacy is safe then you can use it for security. If not then not, and you need to resort to other means to establish secure abstractions. Unfortunately, JavaScript doesn't have many such means, only closures, which aren't always adequate. – Andreas Rossberg Jun 02 '15 at 05:42
  • @AndreasRossberg yeah, I assume one can't use it to protect against XSS attacks, though I'm no expert. But I'm used to C++ and Java, where private variables are merely *not straightforwardly accessible* (except in the case of sandboxed Java, where it's not possible except through security holes) so I'm not that bummed about ES6 symbols. – Andy Jun 02 '15 at 14:55
  • 1
    @Andy, every approach to concealment in JS is *only* about limiting developers from crashing into each other's worlds. If it could also handle privacy issues, I believe we would have seen ***a lot simpler*** client security models (just think of all the man hours lost to debugging origin policies, incomplete/incorrect request/response headers, managing certificates...) – Filip Dupanović Nov 14 '15 at 19:43
  • 1
    @Esailija, **Security is all about communication**. Does it matter if you store your secure computer in an air-gapped private network if the attacker has the ability to communicate to that private network? As for code, ... – Pacerier Mar 22 '17 at 23:19
  • ... imagine if I load user-generated code into my app. If they have no ability to access private areas, then after running the user-generated code **we can assume that the private parts of the exposed *environment* (read: objects) are untouched**. Without private capabilities, we would either have to recreate an **artificial** sandbox copy of the entire environment, or we would have to parse the user-generated code and reconstruct a "safe" version of the user-generated code before running it. – Pacerier Mar 22 '17 at 23:26
  • 1
    @AndreasRossberg, You are missing one important word: "*Leaking private state through* **unprivileged** *reflection should be considered a bug*". The issue here is while the meaning of "unprivileged" is well-defined, the meaning and scope of "reflection" is not. Also, dynamic (as opposed to static/syntactic) management of privileges is a tasty attack vector for attackers which is why Java ain't secure. – Pacerier Mar 22 '17 at 23:33
  • 1
    Sure, they may be found via reflection, but if some developer is hell bent on performing reflection in order to access some variable, let them. They pay for the consequence should the implementation of that variable or its visibility ever change. – Johann May 24 '17 at 06:54
  • @AndroidDev, unfortunately, that's not how it often plays out in practice. The reality is that downstream clients inevitably start relying on your internals, and once there are enough such clients, or a large enough one, you can no longer afford to break them. – Andreas Rossberg May 24 '17 at 16:04
  • 3
    I encountered this standpoint several times but it was never supported with references. Was this objective really mentioned in a spec or discussed by its authors? *on the web, encapsulation sometimes is about security, too* - it's never about security in JS because the language itself provides no security. The only thing that encapsulation affects is the amount of code that has to be copied and pasted by a trespasser if private member cannot be reflected. – Estus Flask Apr 08 '18 at 22:10
  • @estus, it was discussed repeatedly on TC39 at the time, and in general, discussions of security as it relates to the design of JavaScript come up constantly and have affected many design decisions. You can read it all up in TC39 meeting notes or es-discuss archives. – Andreas Rossberg Apr 09 '18 at 00:56
125

Symbols do not guarantee true privacy but can be used to separate public and internal properties of objects. Let's take an example where we can use Symbol for having private properties.

Let's take an example where a property of an object is not private.

var Pet = (function() {
  function Pet(type) {
    this.type = type;
  }
  Pet.prototype.getType = function() {
    return this.type;
  }
  return Pet;
}());

var a = new Pet('dog');
console.log(a.getType());//Output: dog
a.type = null;
//Modified outside
console.log(a.getType());//Output: null

Above, the Pet class property type is not private. To make it private we have to create a closure. The below example illustrates how we can make type private using a closure.

var Pet = (function() {
  function Pet(type) {
    this.getType = function(){
      return type;
    };
  }
  return Pet;
}());

var b = new Pet('dog');
console.log(b.getType());//dog
b.type = null;
//Stays private
console.log(b.getType());//dog

Disadvantage of above approach: We are introducing an extra closure for each Pet instance created, which can harm performance.

Now we introduce Symbol. This can help us make a property private without using extra unnecessary closures. Code example below:

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());//Output: dog
a.type = null;
//Stays private
console.log(a.getType());//Output: dog
Flynn
  • 38
  • 7
Samar Panda
  • 4,186
  • 3
  • 25
  • 32
  • 17
    Notice that symbol properties **are not private**! Symbols are *collision-free*. You may want to read the accepted answer. – Bergi Apr 28 '15 at 03:03
  • 4
    Yes, symbol do not guarantee true privacy but can be used to separate public and internal properties of objects. Sorry, forgot to add this point to my answer. Will update my answer accordingly. – Samar Panda Apr 28 '15 at 05:15
  • @SamarPanda, You might as well say that prefixing members with `_` do not guarantee true privacy but can be used to separate public and internal properties of objects. In other words, pointless answer. – Pacerier Mar 22 '17 at 23:39
  • 15
    I wouldn't say pointless, as symbols are by default not enumerable, also it cannot be accessed by 'mistake', while any other key can. – Patrick May 05 '17 at 21:14
  • 8
    I find your answer the only one that actually have an example that makes sense, on why you would want to define the private attribute of the object as a Symbol, instead of just a normal attribute. – Luis Lobo Borobia Sep 20 '18 at 17:17
  • This is certainly not a pointless answer. The TC-39 panel, which includes some pretty well known names, choose to include symbols for reasons such as the one that this answer outlines. Adding a underscore to denote that a property is private, is not like using a symbol. You might not be able to protect a property like you can in Java (per say), but that's not the point, which is what many of the commentators here are failing to understand. Not being able to change a property that an API author didn't intend to have changed is a huge advantage. One that would be unobtainable w/o symbols. – JΛYDΞV Mar 21 '22 at 06:41
56

This post is about the Symbol(), supplied with actual examples I could find/make and facts & definitions I could find.

TLDR;

The Symbol() is the data type, introduced with the release of ECMAScript 6 (ES6).

There're two curious facts about the Symbol.

  • the first data type and only data type in JavaScript which has got no literal

  • any variable, defined with Symbol(), gets unique content, but it's not really private.

  • any data has its own Symbol, and for the same data the Symbols would be the same. More info in the following paragraph, otherwise it's not a TLRD; :)

How do I initialise the symbol?

1. To get a unique identifier with a debuggable value

You can do it either this way:

var mySymbol1 = Symbol();

Or this way:

var mySymbol2 = Symbol("some text here");

The "some text here" string can't be extracted from the symbol, it's just a description for debugging purposes. It doesn't change the behaviour of symbol in any way. Although, you could console.log it (which is fair, since the value is for debugging, so as not to mistake that log with some other log entry):

console.log(mySymbol2);
// Symbol(some text here)

2. To obtain a symbol for some string data

In this case the value of symbol is actually taken into account and this way two symbols may be non-unique.

var a1 = Symbol.for("test");
var a2 = Symbol.for("test");
console.log(a1 == a2); //true!

Let's call those symbols "second-type" symbols. They do not intersect with the "first-type" symbols (i.e. the ones defined with Symbol(data)) in any way.

The next two paragraphs pertain only the first-type symbol.

How do I benefit from using Symbol instead of the older data types?

Let's first consider an object, a standard data type. We could define some key-values pairs there and have an access to the values by specifying the key.

var persons = {"peter":"pan","jon":"doe"};
console.log(persons.peter);
// pan

What if we have two persons with the name Peter?

Doing this:

var persons = {"peter":"first", "peter":"pan"};

wouldn't make much sense.

So, appears to be a problem of two absolutely different persons having a same name. Let's then refer out new Symbol(). It's like a person in real life - any person is unique, but their names can be equal. Let's define two "persons".

 var a = Symbol("peter");
 var b = Symbol("peter");

Now we have got two different persons with the same name. Are our persons different indeed? They are; you can check this:

 console.log(a == b);
 // false

How do we benefit there?

We can make two entries in your object for the different persons and they can't be mistaken in any way.

 var firstPerson = Symbol("peter");
 var secondPerson = Symbol("peter");
 var persons = {[firstPerson]:"first", [secondPerson]:"pan"};

Note:
It's worth to notice, though, that stringifying the object with JSON.stringify will drop all the pairs initialised with a Symbol as a key.
Executing Object.keys won't either return such Symbol()->value pairs.

Using this initialisation, it's absolutely impossible to mistake the entries for the first and second persons. Calling console.log for them will correctly output their second names.

 console.log(persons[a]);
 // first
 console.log(persons[b]);
 // pan

When used in object, how it is different compared to defining non-enumerable property?

Indeed, there already existed a way to define a property to be hidden from Object.keys and enumeration. Here it is:

var anObject = {};
var fruit = "apple";    

Object.defineProperty( anObject, fruit, {
    enumerable: false,
    value: "green"
});

What difference does Symbol() bring there? The difference is that you can still get the property defined with Object.defineProperty in the usual way:

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //green
console.log(anObject.apple); //green

And if defined with Symbol as in previous paragraph:

fruit = Symbol("apple");

You will have an ability to receive its value only if knowing its variable, i.e.

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //undefined
console.log(anObject.apple); //undefined

Moreover, defining another property under the key "apple" will make the object drop the older one (and if hard-coded, it could throw an error). So, no more apples! That's a pity. Referring the previous paragraph, the Symbols are unique and defining a key as Symbol() will make it unique.

Type conversion and checking

  • Unlike other data types, it's impossible to convert the Symbol() to any other data type.

  • It's possible to "make" a symbol based on primitive data type by calling Symbol(data).

  • In terms of checking the type, nothing changes.

     function isSymbol ( variable ) {
         return typeof someSymbol === "symbol";
     }
    
     var a_Symbol = Symbol("hey!");
     var totally_Not_A_Symbol = "hey";
    
     console.log(isSymbol(a_Symbol)); //true
     console.log(isSymbol(totally_Not_A_Symbol)); //false
    
Lino
  • 19,604
  • 6
  • 47
  • 65
nicael
  • 18,550
  • 13
  • 57
  • 90
  • Was this migrated from SO Documentation? – Knu Apr 14 '18 at 23:57
  • 4
    @KNU it wasn't; I've gathered the info and wrote this answer myself – nicael Apr 15 '18 at 20:13
  • 1
    Really beautiful answer! – Mihai Alexandru-Ionut Apr 17 '18 at 13:04
  • 5
    Great answer on Symbol, however I still don't know why would I use object with symbol keys instead of an array. If I have multiple person like {"peter":"pan"} {"john":"doe"} it feels bad for me to put them in one object. For the same reason as I don't make classes with duplicated properties like personFirstName1, personFirstName2. This combined with the inability to stringify it I don't see benefits just disadvantages. – eldo Mar 07 '19 at 07:37
52

Symbols are a new, special kind of object that can be used as a unique property name in objects. Using symbols instead of a strings allows different modules to create properties that don’t conflict with one another. Symbols can also be made effectively private, so that their properties can’t be accessed by anyone who doesn’t already have direct access to the symbol.

Symbols are a new primitive, just like the number, string, and boolean primitives. Unlike the other primitives, symbols do not have a literal syntax (e.g. how string has '') — the only way to create them is with the Symbol constructor in the following way:

let symbol = Symbol();

In reality, symbols are just a slightly different way to attach properties to an object — you could easily provide the well-known symbols as standard methods, just like Object.prototype.hasOwnProperty, which appears in everything that inherits from Object.

Here are some of the benefits of the Symbol primitive type.

Symbols have debuggability built in

Symbols can be given a description, which is really just used for debugging to make life a little easier when logging them to a console.

Symbols can be used as object keys

This is where symbols get really interesting. They are heavily intertwined with objects. Symbols can be assigned as keys to objects, meaning you can assign an unlimited number of unique symbols to an object and be guaranteed that these will never conflict with string keys, or other unique symbols.

Symbols can be used as unique values

Let’s assume you have a logging library, which includes multiple log levels such as logger.levels.DEBUG, logger.levels.INFO, logger.levels.WARN and so on. In ES5 code you’d like make these strings (so logger.levels.DEBUG === 'debug'), or numbers (logger.levels.DEBUG === 10). Both of these aren’t ideal as those values aren’t unique values, but symbols are! So logger.levels simply becomes:

log.levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');

Read more in this great article.

chharvey
  • 8,580
  • 9
  • 56
  • 95
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
  • 14
    I'm not sure I understand your example, and why would you need `log.levels = {DEBUG: Symbol('debug')` and not simply `log.levels = {DEBUG:'debug'}`. at the end it's the same. I think it's worth mentioning that Symbols are invisible when iterating over an Object's keys. that's their "thing" – vsync Sep 18 '18 at 12:01
  • 1
    One benefit is someone cannot *accidentally* use a literal and believe it'd work forever. (Note that this is not a really strong argument, as one can simply use `{}` and achieve same result (as unique value), or maybe a literal is preferred in that project, or you can say one need to read the doc first. ) I personally think it provide a good readability of unique meaning in code – apple apple Jun 06 '20 at 04:11
  • note when used as unique value, object literal also have *debuggability built in* i.e. `Symbol("some message")` becomes `{message:'some message'}`, arguably object does better here as you can add multiple field. – apple apple Jun 06 '20 at 04:16
20

Here is how I see it. Symbols provide 'an extra level of privacy', by preventing the keys/properties of an object from being exposed through some popular methods such as Object.keys() and JSON.stringify().

var age = Symbol();  // declared in another module perhaps?
class Person {
   constructor(n,a){
      this.name = n;
      this[age] = a;  
   }
   introduce(){
       console.log(`My name is ${this.name}. I am ${this[age]-10}.`);
   }
}
var j = new Person('Jane',45);
j.introduce();  // My name is Jane. I am 35.
console.log(JSON.stringify(j)); // {"name":"Jane"}
console.log(Object.keys(j)); // ["name"]
console.log(j[age]); // 45   (well…only if you know the age in the first place…)

Although given an object per se, such properties can still be exposed through reflection, proxy, Object.getOwnPropertySymbols() etc., there is no natural means to access them through a few direct methods, which may be sufficient sometimes from an OOP perspective.

Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
3

A JS symbol is a new primitive data type. They are tokens that serve as unique IDs. A symbol can be created using the Symbol constructor. Take for instance this snippet from MDN:

// The symbol constructor takes one optional argument, 
// the descriptions which is used for debugging only.
// Here are two symbols with the same description
let Sym1 = Symbol("Sym");
let Sym2 = Symbol("Sym");
  
console.log(Sym1 == Sym2); // returns "false"
// Symbols are guaranteed to be unique.
// Even if we create many symbols with the same description,
// they are different values.

It is often handy to use symbols as unique object property keys, for example:

let obj = {};
let prop = Symbol();

obj[prop] = 123;  // the symbol prop is assigned 123
obj.prop  = 456;  // the string prop is assigned 456

console.log(obj.prop, obj[prop]); // logs 456, 123
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
1

Here's how I would describe Symbols, from my point of view, and also why I think they are useless trash:


Quick explanation:

Symbols are the JavaScript equivalent of built-in, unique, enumeration values with a "description" string which has no bearing on the value nor uniqueness of the Symbol. But the behavior changes substantially depending on whether you're using Symbol() or Symbol.for()!!!

As others have already pointed out:

mySymbol = Symbol("blue");
mySymbol.description //"blue"
mySymbol == mySymbol //true

//Unlike what you might expect...
mySymbol != Symbol("blue")

//So, Symbol() is creating a new Symbol each time.
Symbol("blue") != Symbol("blue")

See also, regarding enumeration of objects containing Symbols:


Problem One...

Now that all might seem fine and workable for you, and it is, up until you discover Symbol.for()...:

The Symbol.for() static method searches for existing symbols in a runtime-wide symbol registry with the given key and returns it if found. Otherwise a new symbol gets created in the global symbol registry with this key.

a = Symbol("blue");
a.description //"blue"
b = Symbol("blue");
c = Symbol.for("blue");
c.description //"blue"
d = Symbol.for("blue");

a != b //We already know this one, but then...
a != c //Oh? So they're different. Yep!

//But then maybe it's the most recent...?
b != c //Nope!
b != d //Also nope!

c == d //This is the ONLY permutation that is equivalent.

Thus, while Symbol() creates a Symbol with a totally-value-and-uniqueness-irrelevant "description" string, Symbol.for() creates a Symbol with a globally-mapped "description" string..... But, because Symbol()'s description string is irrelevant, Symbol() and Symbol.for() are operating in two entirely separate worlds, all the while using the same Symbol type and similar terminology.....!

Super clear, thanks JavaScript overlords!


More Problems...

So to clarify, here's why Symbols are useless...:

  • Suppose you come across a Symbol. You have to use this to determine at runtime which method of Symbol creation was utilized:
//Method A: Symbol()
Symbol.keyFor(Symbol("blue")) //undefined

//Method B: Symbol.for()
Symbol.keyFor(Symbol.for("blue")) //blue
  • If they used Method A, and you want to use it, you had better hope your code has access to that particular Symbol reference...

  • If they used Method B, you had better hope that no other code in your codebase is using that Symbol string, since it's global...

  • The main idea behind using Symbols is to avoid name/key collisions i.e. in future code... but how is that any better than the already existing types?

  • Some would answer ^ this question with the fact that Symbols will not be enumerated like the other types (see links from earlier in this answer). Okay? And that's helpful how? Just use Object.defineProperty() and set enumerable to false. All Symbols do is add further unnecessary complication to the language, because now you have to use something different like Reflect.ownKeys() to access all properties of an object... As MDN says...:

[Reflect.ownKeys()] is the only way to get all own properties – enumerable and not enumerable, strings and symbols — in one call, without extra filtering logic. For example, Object.getOwnPropertyNames() takes the return value of Reflect.ownKeys() and filters to only string values, while Object.getOwnPropertySymbols() filters to only symbol values.

  • They boast about how Symbols can't be modified nor have properties assigned (and thus also not reassigned) on them (something which is already achievable with either basic JS strings or also Object.freeze()...), but that's more of a hindrance than a feature. For example, you might want to do something like:
myEnum = [
  { name: "blue" },
  { name: "red" }
];

//Can't do this with Symbols...:
for (let index = 0; index < myEnum.length; ++index) {
  myEnum[index].value = index;
}

/*
  which would turn it into:
  myEnum = [
    { name: "blue", value: 0 },
    { name: "red", value: 1 }
  ];
*/
  • Symbol() does accept other types of descriptions (or nothing at all) in its constructor function (which doesn't use new...), but it stringifies whatever you put in it, e.g.:
Symbol({ val: 5 }).description == "[object Object]"

So useful!


Conclusion

So, my recommendation? Don't ever even use Symbols, if you can help it. Use basic {} objects, classes, [] arrays, strings, numbers - basically anything else - instead. Instead of JS making enums easier like they should have, they added this complicated and more useless than useful Symbol crap instead.

Andrew
  • 5,839
  • 1
  • 51
  • 72
0

Symbols have two main use cases:

  1. “Hidden” object properties. If we want to add a property into an object that “belongs” to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in for..in, so it won’t be accidentally processed together with other properties. Also it won’t be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite.

    So we can “covertly” hide something into objects that we need, but others should not see, using symbolic properties.

  2. There are many system symbols used by JavaScript which are accessible as Symbol.*. We can use them to alter some built-in behaviors. For instance, ...... Symbol.iterator for iterables, Symbol.toPrimitive to setup object-to-primitive conversion and so on.

Source