JavaScript Symbols Demystified

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Professional Modern JavaScript Lessons

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36

JavaScript Symbols Demystified

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Fundamentals

const alpha = Symbol();
const beta = Symbol();

console.log(alpha === beta); // false

const uno = Symbol('espaniol');
const duo = Symbol('espaniol');

console.log(uno === duo); // false

console.log(alpha === alpha); // true
console.log(uno === uno); // true

console.log(uno.toString()); // 'Symbol(espaniol)'

console.log(typeof alpha); // 'symbol'

Symbols as Object Keys

const one = Symbol('one');
const uno = Symbol('one');

const keysDemo = {
[one]: 'alpha',
[uno]: 'beta',

one: 'gamma',
['one']: 'delta',
};

console.log(keysDemo.one); // 'delta'
console.log(keysDemo[one]); // 'alpha'
console.log(keysDemo[uno]); // 'beta'

console.log(keysDemo);
// { one: 'delta', [Symbol(one)]: 'alpha', [Symbol(one)]: 'beta' }

Not Enumerable

const gamma = Symbol('gamma');

const enumerationDemo = {
alpha: 'alpha',
beta: 'beta',
[gamma]: 'gamma',
};
console.log(enumerationDemo[gamma]); // 'gamma'
console.log(Object.keys(enumerationDemo)); // ['alpha', 'beta']


for (const key in enumerationDemo) {
const value = enumerationDemo[key];
console.log(`${key}:${value}`);
// alpha:alpha beta:beta
}
console.log(JSON.stringify(enumerationDemo));
// {"alpha":"alpha","beta":"beta"}

Safe Object Extension

const person = {
id: '123',
name: 'John',
};

const dbId = Symbol('id');
person[dbId] = '456';

console.log(Object.entries(person)); // [ [ 'id', '123' ], [ 'name', 'John' ] ]
console.log(person[dbId]); // 456

const cacheId = Symbol('id');
person[cacheId] = '789';

console.log(person.id); // 123
console.log(person[dbId]); // 456
console.log(person[cacheId]); // 789

Well Known Symbols

console.log(Symbol.hasInstance); // Symbol(Symbol.hasInstance)

class Alpha { }
class Beta { }

const alpha = new Alpha();

console.log(alpha instanceof Alpha); // true
console.log(alpha instanceof Beta); // false

console.log(Alpha[Symbol.hasInstance](alpha)); // true
console.log(Beta[Symbol.hasInstance](alpha)); // false

class ArrayLike {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance)
|| typeof instance?.length === 'number';
}
}

console.log([1, 2, 3] instanceof ArrayLike); // true
console.log({ length: 2 } instanceof ArrayLike); // true
console.log({ length: '2' } instanceof ArrayLike); // false

Sharing Symbols

const one = Symbol('english');
const two = Symbol('english');
console.log(one === two); // false

const uno = Symbol.for('spanish');
const dos = Symbol.for('spanish');
console.log(uno === dos); // true

const joseph = {
name: 'Joseph',
[Symbol.for('spanish')]: true
};

console.log(JSON.stringify(joseph)); // {"name":"Joseph"}

console.log(joseph[uno]); // true
console.log(joseph[Symbol.for('spanish')]); // true
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Symbol is one of the core primitive types and a fundamental building block. For some of the more modern features within JavaScript, we can create a symbol by simply invoking the built-in JavaScript symbol function. Every time we create a symbol, it is guaranteed to be unique. So Alpha and B Tower here are never going to be equal to one another. You can also pass in a string to the symbol function, and this doesn't actually change any of the equality semantics. So here Uno and Duo are still going to be different from one another. They are still going to be two distinct symbols. Only if you have an original reference to the symbol that we've created,

00:34

will it be equal to itself. So question that you might have is what is the point of passing a string to a symbol if it's not going to make it any more or less unique? Well, it's really useful for debugging purposes. When we convert a symbol to a string, we can see the name that was passed in to create it. Notice that we said that symbol is a core primitive type within JavaScript, which means that it has its own result for the type of operator. Unlike some of the other built-ins that we have seen, it has not returned an object. It returns its own special string, which is symbol beyond numbers and strings.

01:06

Symbols are the only other primitives that have first class support to be used as an object property key within JavaScript. Here we are creating two symbols, both with the description of the stringer one, but as we know, these are still two distinct symbols. We can use them as keys within objects by using the computed properties syntax. And here one is going to point to alpha and Uno is going to point to beta. And since they're unique, they're not going to conflict with one another. And this is different from other object properties. For example, here we have a property one, and this will definitely conflict with some computed property that has the

01:40

string value of one. For example, here, gamma is going to get overwritten by delta. So that's a really strong advantage of using symbols because they are unique, they do not conflict with one another and they do not conflict with any of the string properties. Keys demo symbol one is going to give us alpha keys demo symbol uno is going to give us Peter, and we can see that in the final object output, the string properties fought with one another and delta one, whereas the symbol properties can peacefully coexist. Symbol keys within objects don't behave like standard string keys in that symbols offer a basic form of information hiding. When it comes to enumeration,

02:16

we start off with a simple symbol called gamma, and then we create an object that has a few identifier based properties, alpha and beta, and then the computed property for gamma. Of course, we can access the gamma property by using the gamma symbol, and of course we get back the value which is the string gamma, but the gamma property does not show up in general iteration of the object. For example, if you use the object or keys method, we only see the string properties alpha and beta. Similarly, if you use the four in loop to loop over the keys of the object, we will only see alpha and beta, no sign of camera anywhere. And if you try to serialize this object using JS N,

02:52

since of course Jason does not support any keys other than strings, we will only see alpha and beta. No sign of camera here either. So in summary, when you add a symbol to an object, it mostly remains hidden to standard JavaScript code unless you have a reference to that symbol. Because symbols are sort of hidden unless you have a reference to them and they don't conflict with existing object properties. You can use symbols to safely add properties to objects without worrying about that information leaking or mistakenly overriding existing properties. For example, hey, we have a very simple person object that has an ID and a name,

03:27

and we want to store this in a database, so we assign a database ID to it as well, and we could do that with an id, but it will conflict with whatever ID is there. So we can be smart and use a symbol to define that id, and we don't actually even need to look at the person object. We know that the symbol is going to be unique every single time. So we are not going to conflict with whatever was already there. And as far as existing JavaScript code is concerned, it's going to be hidden from that as well. They will only see the existing properties, which were the old ID and the name, but if we have a reference to the symbol,

03:59

of course we can still read that value that we stored, which is 4, 5, 6, and someone can come along and add their own caching ID as well by using another symbol. And now the person object has the id, has the d b ID and the caching id, and they will not be conflicting with one another. Since symbols do not conflict with other properties, a modern JavaScript relies on well-known symbols to offer certain runtime features. This makes them easy to access without conflicting with existing object keys. The well-defined symbols exist as static properties on the symbol object. And one such example is the has instance symbol.

04:34

To demonstrate how this is used internally, we create two simple classes, alpha and beta, and let's just create an instance of alpha. We've looked at the built-in instance of operator within JavaScript, and of course our alpha variable is an instance of the alpha class, so that will return true, but alpha instance of beta will return false. This actually internally uses the Hass instance symbol. If we access the Hass instance property on the alpha class and passing the alpha object, that returns true. And if we do the same thing with the beta class and passing the alpha object, it returns false. And this is actually what is happening behind the scenes.

05:08

When we use the instance of operator, in fact, let's override what the instance of does for a custom class. We create this class called array like, and then we add a static member for symbol has instance, which will be a function that gets passed in an instance, and then we return to if that instance is an array or it has a length property, which is of type number. So if you use an array with an instance of array like array is array, we'll return true and therefore we get back true. And similarly, if we do an object with a length property pointing to the number two instance of array, like the instance length is of type number,

05:43

and therefore we get back true. But for anything else, if it's not an array or the length property is a not of type number, we will get back false. And I'm not saying that you should do something like this. In fact, unless you are building a domain specific Language, you probably shouldn't. But I wanted to demonstrate how instanceof is completely controlled by a well-known symbol. If you need to share symbols but can pass a reference, for example, over browser iframes, then JavaScript provides a global symbol registry that enables you to obtain a reference to the same symbol for a given string value.

06:16

We know that when we create two symbols with the same string, they are still completely unique. The string is only there for debugging purposes, but there is a special method on the symbol called a four that does something different given a string. It checks if a symbol has been defined for that value in the global registry, and if it has it returns that otherwise it creates it and adds it to the registry. In this particular case, a new symbol for the string Spanish will be created and registered. So the next time someone calls symbol dot four Spanish, they will get back the same reference. So UNO will be equal to those.

06:51

It's still a real symbol, so if we create an object that uses it as a member, it'll be hidden for most of JavaScript. For example, serialization and enumeration. And of course we can still access that property if we have a reference to the symbol, but even if we don't have that reference because we couldn't pass it around or it was too difficult to pass it around, we can ask the registry for that reference by using symbol four and we will get that reference to the symbol that we wanted and we can use it to read the property value. I hope you enjoyed this tutorial. As always, thank you for joining me and I will see you in the next one.

Professional Modern JavaScript

Professional Modern JavaScript

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36