Skip to content

Instantly share code, notes, and snippets.

@androide-osorio
Last active September 9, 2016 15:53
Show Gist options
  • Save androide-osorio/90b833cf60186a55e43b3a742ca7db77 to your computer and use it in GitHub Desktop.
Save androide-osorio/90b833cf60186a55e43b3a742ca7db77 to your computer and use it in GitHub Desktop.
ES2015 Roadtrip to awesomeness: Symbols
/**
______ _____ ___ ___ __ _____ _____ _ _
| ____| / ____| |__ \ / _ \ /_ | | ____| _ / ____| | | | |
| |__ | (___ ) | | | | | | | | |__ (_) | (___ _ _ _ __ ___ | |__ ___ | | ___
| __| \___ \ / / | | | | | | |___ \ \___ \ | | | | | '_ ` _ \ | '_ \ / _ \ | | / __|
| |____ ____) | / /_ | |_| | | | ___) | _ ____) | | |_| | | | | | | | | |_) | | (_) | | | \__ \
|______| |_____/ |____| \___/ |_| |____/ (_) |_____/ \__, | |_| |_| |_| |_.__/ \___/ |_| |___/
__/ |
|___/
*/
// a new primitive type that allows to create unique
// identifiers (like in ruby, but less cool) and they
// help avoiding naming collisions.
const sym = Symbol('Andrew');
console.log(sym); // output -> Symbol(Andrew)
// the parameter in the Symbol() constructor is just
// a descriptor, to identify a symbol from others
// All symbols are unique, even those with the same descriptor.
// Descriptors only have debugging purposes.
// NOTE: if you lose a reference to a symbol, you won't be able to
// continue using it
const sym2 = Symbol('Andrew');
console.log(sym === sym2); // false
// you can use symbols to create unique properties
// on an object
const classRoom = {
teacher: 'Andrew',
[Symbol('Mark')]: { grade: 50, gender: 'male' },
[Symbol('Olivia')]: { grade: 80, gender: 'female' },
[Symbol('Olivia')]: { grade: 40, gender: 'undecisive' }
};
console.log(classRoom);
// Symbols are NOT enumerable, so they cannot be enumerated
// through any loop. Use symbols to store "private" data into objects,
// since they cannot be enumerated and not so easily obtained
console.log('start loop');
// this loop will only output the teacher's name
for(let student in classRoom) {
let studentData = classRoom[student];
console.log(studentData);
}
console.log('end loop');
console.log(Object.getOwnPropertyNames(classRoom)); //-> ['teacher']
classRoom.hasOwnProperty(Symbol('Mark')); // -> false
// to obtain symbol properties and their values from objects, use
// Object.getOwnPropertySymbols()
const syms = Object.getOwnPropertySymbols(classRoom); //-> [Symbol(Mark), Symbol(Olivia), Symbol(Olivia)]
const data = syms.map(symbol => classRoom[symbol]);
console.log(data); // outputs student data
// --------------------------------------------------
// Caveat: creating a symbol in the global registry
// the Symbol.for() method can be used to register or fetch a symbol
// into a "global symbol registry" that is cross realm
// (i.e: it is shared through frames and workers).
const fooSym1 = Symbol('foo');
const fooSym2 = Symbol('foo');
console.log(fooSym1 === fooSym2); // false
// using Symbol.for()
const fooSymGlobal1 = Symbol.for('foo');
// this line does not create a new symbol.
// It just fetches the Symbol('foo') already created
// in the global symbol registry
const fooSymGlobal2 = Symbol.for('foo');
console.log(fooSymGlobal1 === fooSymGlobal2); // true
// Symbol.for() is cross-realm
// extracted from: https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/
iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);
console.log(iframe.contentWindow.Symbol === Symbol); // false
console.log(iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo')); // true
/**
* How do I know if a Symbol is in the global registry??
*
* use Symbol.keyFor().
* This method will return the key (as a string) with which a symbol
* in the global registry is identified. If such symbol
* is not in the global registry (aka: a local symbol),
* the method will return 'undefined'.
*/
const localFooSymbol = Symbol('foo');
const globalFooSymbol = Symbol.for('foo');
// key for local Symbol(foo) must be undefined:
console.log(Symbol.keyFor(localFooSymbol) === undefined); // -> true
// key for global Symbol(foo) is "foo"
console.log(Symbol.keyFor(globalFooSymbol) === 'foo'); // -> true
@androide-osorio
Copy link
Author

All of these use cases and explanations were extracted from ES6 for everyone course by Wes Bos, and this amazingly thorough article by Keith Cirkel. More information about Symbols (which I didn't include in the gist for the sake of brevity) can be found in that article.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment