DEV Community

Cover image for Javascript Symbols
Lucy Love
Lucy Love

Posted on • Updated on • Originally published at oh-no.ooo

Javascript Symbols

The good perk of having a lot of people who code around you is that you end up discussing things that you don't get to see on a day-to-day basis as a simpleton frontend developer.

This time, I landed on the concept of symbols in JavaScript, which is something I don't have to deal with at work, but something that JavaScript offers and it'd be nice to understand what it is and why it is :D

What is a Symbol?

A symbol is a unique and immutable data type in JavaScript.

If that doesn't tell you anything (which indeed didn't for me), know that a symbol is one of the JavaScript primitive data types just as string, boolean, integer etc. but it works like a special identifier to access object properties, and it can be used more or less like a property key.

Let's imagine that we have an object where we store a person's name, an id and their age.

let person = {
  name: "Sophia",
  id: 12345678,
  age: 24, // (yes, I'm a trailing comma person)
};
Enter fullscreen mode Exit fullscreen mode

If we want to access the value of the id property, we'd just do:

console.log(person.id); // will give us 12345678
Enter fullscreen mode Exit fullscreen mode

It is fair to assume that id won't change as often as the other characteristics of a person, and tailor our work around that assumption.

Let's try to use a symbol as a key by creating it. This can be done using the Symbol() constructor:

let symbolIDKey = Symbol("id");
let person = {
  name: "Sophia",
  [symbolIDKey]: 12345678,
  age: 30,
};
console.log(person[symbolIDKey]); // outputs 12345678
Enter fullscreen mode Exit fullscreen mode

You could, in theory, use no "id" parameter (properly referred as descriptor), but if you were to use more than one symbol key, it'd be more challenging to know which is which.

Why symbols then?

Using symbols as object keys will provide you with a unique and guaranteed way of accessing object properties, even if other code adds or modifies properties with the same key.

For example:

let symbolIDKey = Symbol("id");
let person = {
  name: "Sophia",
  [symbolIDKey] = 12345678,
  age: 30,
};
Enter fullscreen mode Exit fullscreen mode

Some other code, for whatever reason, will try to do

person.id = 00000000;
Enter fullscreen mode Exit fullscreen mode

You will be left with

let symbolIDKey = Symbol("id");
let person = {
  name: "Sophia",
  [symbolIDKey] = 12345678,
  age: 30,
  id: 00000000,
};

console.log(person.id); // will output 00000000
console.log(person[symbolIDKey]); // will output our more expected 12345678
Enter fullscreen mode Exit fullscreen mode

The symbol key is allowing us to preserve the original value even if some other code might try to alter the property id.

With symbols you can add private properties to an object that are not intended to be modified or accessed directly by other code.

But beware! Symbols keys are not enumerated, which means that they do not show up in the list of keys of the object if you try to access them by loops and mappings.

You cannot even access the symbol keys of an object with keys() nor with getOwnPropertyNames()!

You will need to be aware of the structure of your object and if you need to access the symbol keys, you'll have to use getOwnPropertySymbols().

...

And that's it! I don't see myself using this approach anytime soon, but it's good to know that, should I be concerned with the integrity of the data I work with, there are ways for me to preserve some information in the flimsy world that JavaScript often creates for us.

Sources and inspiration

Top comments (8)

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

The best way I could probably put it is: Symbols are (like objects) unique and can't be "recreated", but (unlike objects) they don't store any other data and instead can be used in most places where strings can be used. Their entire point is just being unique.

And then some example like the one you have.

I don't get to use symbols a whole lot, but they're really cool when you're dealing with very extensible code where lots of people might come up with similar names for strings so strings might clash.

But it's also cool when you want your own "special" values; I use it in my HTML generation library to represent "nothing" so you can write condition ? "Warning: condition is true" : empty. This way I can output a warning for null or undefined because those might be mistakes, but don't have to check for some weird string like "__!empty!__" and just hope that nobody wants to put that as actual text in their HTML.

They're also skipped in some functions that deal with object keys, by the way:

const obj = {
   foo: "String",
   [Symbol("foo")]: "Symbol"
}
Object.keys(obj) // ['foo']
Object.values(obj) // ['String']
Object.getOwnPropertyNames(obj) // ['foo']
Reflect.ownKeys(obj) // ['foo', Symbol(foo)]
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mahdava profile image
Lucy Love

Thank you so much for the very insightful comment!! It's so nice actually to hear a more realistic scenario on why people would use symbols and what problem they're trying to solve!

As to be expected, it comes in handy especially when you're extending your code with third-parties work!!

You got me curious at your HTML generation library :O Is there something I could check about it? I'm always hella curious about these type of projects! 😍

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Yea, it's on github github.com/DarkWiiPlayer/skooma-js... 😁

It gets used further down in the same file around line 210

Thread Thread
 
mahdava profile image
Lucy Love

Thank you so much!! This is such an amazing use case for symbols!

You have so many interesting Lua projects, I've been meaning to try lua out for some time and everything you have on your GitHub is incredibly inspiring!

Such amazing work, I am so flattered I had chances to have a look at it!! 😍

Collapse
 
panino5001 profile image
Andrés Fernández

Replace this in your example:
[symbolIDKey] = 12345678,
For this:
[symbolIDKey] : 12345678,

Collapse
 
mahdava profile image
Lucy Love

Thank you so much for the correction Andrés, really appreciated!

Collapse
 
jonrandy profile image
Jon Randy 🎖️

Another nice usage of symbols is using them to name methods on built-in prototypes. Done this way, you can safely add functionality to them without any danger of name collisions with future JS version, or other libraries. I made a whole library based on this capability:

Symbols are super useful!

Collapse
 
mahdava profile image
Lucy Love

Thank you so much for sharing your article, how insightful!!

For someone that has never had chances to use symbols in a meaningful way, I am so thankful to see so many useful situations where they bring in a lot of value!

Amazing work!! And such a great job with Metho!! 🙇‍♂️