• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using global symbols
2
3ES6 introduced a new type: `Symbol`. This new type is _immutable_, and
4it is often used for metaprogramming purposes, as it can be used as
5property keys like string. There are two types of
6symbols, local and global.
7Symbol-keyed properties of an object are not included in the output of
8`JSON.stringify()`, but the `util.inspect()` function includes them by
9default.
10
11Learn more about symbols at
12<https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Symbol>.
13
14## `Symbol(string)`
15
16Symbols created via `Symbol(string)` are local to the caller function.
17For this reason, we often use them to simulate private fields, like so:
18
19```js
20const kField = Symbol('kField');
21
22console.log(kField === Symbol('kField')); // false
23
24class MyObject {
25  constructor() {
26    this[kField] = 'something';
27  }
28}
29
30module.exports.MyObject = MyObject;
31```
32
33Symbols are not fully private, as the data could be accessed anyway:
34
35```js
36for (const s of Object.getOwnPropertySymbols(obj)) {
37  const desc = s.toString().replace(/Symbol\((.*)\)$/, '$1');
38  if (desc === 'kField') {
39    console.log(obj[s]); // 'something'
40  }
41}
42```
43
44Local symbols make it harder for developers to monkey patch/access
45private fields, as they require more work than a property prefixed
46with an `_`. Monkey patching private API that were not designed to be
47monkey-patchable make maintaining and evolving Node.js harder, as private
48properties are not documented and can change within a patch release.
49Some extremely popular modules in the ecosystem monkey patch some
50internals, making it impossible for us to update and improve those
51areas without causing issues for a significant amount of users.
52
53## `Symbol.for`
54
55Symbols created with `Symbol.for(string)` are global and unique to the
56same V8 Isolate. On the first call to `Symbol.for(string)` a symbol is
57stored in a global registry and easily retrieved for every call of
58`Symbol.for(string)`. However, this might cause problems when two module
59authors use the same symbol
60for different reasons.
61
62```js
63const s = Symbol.for('hello');
64console.log(s === Symbol.for('hello'));
65```
66
67In the Node.js runtime we prefix all our global symbols with `nodejs.`,
68e.g. `Symbol.for('nodejs.hello')`.
69
70Global symbols should be preferred when a developer-facing interface is
71needed to allow behavior customization, i.e., metaprogramming.
72