ES6 of the Week

This Week's Episode:
maps and sets
Key : Value
Some ways we store key/value pairs...
- HashMaps
- dictionaries
- hashes
Object downsides
- Keys must be strings in ES5
- Challenges with built-in method collisions
- Objects are not inherently iterable

Sets
- ordered lists of values which contain no duplicates
- primitive values AND object references
- maintain order of insertion
- can check their equality at a high level
On your mark, get set...
let _set = new Set(); // n.b. set is a reserved word, so I'm calling my variable _set
// Set.prototype.add
_set.add("string").add(42);
// store object references
let obj = { a : 1 };
_set.add(obj);
// Set.prototype.size
_set.size // => 3
_set.add(42) // no repeats
_set.size // => 3
// Set.prototype.has
_set.has("string") // true
_set.has(obj) // true, wowzers!
_set.has(21) // false
// Iterate using for...of
for (let item of _set) console.log(item); // logs in insertion order
// Set.prototype.delete and Set.prototype.clear
_set.delete("string"); // remove a single item
_set.clear(); // wipe the set clean
Arrays
Could have duplicates
Actually an object
Iterate with for loop
Sets
Unique values
No baggage
Iterate with for...of
Setting the bar
var bar = ["value1", "value2", "value3"];
// Use the regular Set constructor to transform an Array into a Set
var foo = new Set(bar);
foo.has("value1"); // returns true
// Use the spread operator to transform a set into an Array.
console.log([...foo]); // Will show you exactly the same Array as bar
// but what if bar has duplicate values?
var bar = ['one fish', 'two fish', 'red fish', 'blue fish', 'blue fish'];
var foo = new Set(bar);
console.log([...foo]) // <- ['one fish', 'two fish', 'red fish', 'blue fish']
Equality
let persons = new Set();
let randalf = {id: 1, name: 'randalf'};
persons
.add(randalf)
.add(randalf);
console.log(`I have ${persons.size} person`)
// => I have 1 person
console.log([...persons]);
// => [[object Object] {
// id: 1,
// name: "randalf"
//}]
persons.add({id: 1, name: 'randalf'});
console.log(`I have ${person.size} persons?!?`)
// => I have 2 persons?!?
console.log([...persons]);
/*
*= [[object Object] {
id: 1,
name: "randalf"
}, [object Object] {
id: 1,
name: "randalf"
}]
*/

Maps
Are key-value maps
Keys can contain object references, functions, or whatever!
Has handy methods (get the size or iterate)
Follow the Map!
let _map = new Map();
// Map.prototype.set
_map.set('a', 1);
_map.set('b', 2);
let objKey = { 'c' : 3 };
_map.set(objKey, 4);
// Map.prototype.get
_map.get('a'); // => 1
_map.get(objKey); // => 4
// Map.prototype.size - much easier than using Object.hasOwnProperty!
_map.size; // => 3
// Iterate over keys using Map.prototype.keys
for (let key of _map.keys()) console.log(key);
// Iterate over values using Map.prototype.values
for (let value of _map.values()) console.log(value);
Follow the Map!
var map = new Map([
[new Date(), function today () {}],
[() => 'key', { full: 'stack' }],
[Symbol('items'), [1, 2]]
])
var items = [
[new Date(), function today () {}],
[() => 'key', { full: 'stack' }],
[Symbol('items'), [1, 2]]
]
var map = new Map()
items.forEach(([key, value]) => map.set(key, value))
var map = new Map()
map.set('g', 'o')
map.set('t', 'e')
map.set('a', 'm')
for (let [key, value] of map) {
console.log(`${key}: ${value}`)
}
// <- 'g: o'
// <- 't: e'
// <- 'a: m'
Keys, keys, keys...
var map = new Map()
map.set('a', 'a')
map.set('a', 'b')
map.set('a', 'c')
var map = new Map([[1, 'a']])
console.log(map.has(1))
// <- true
console.log(map.has('1'))
// <- false
console.log([...map])
// <- [['a', 'c']]
Objects
Has a prototype (default key)
Keys are strings or symbols
Cannot get size easily
Maps
No prototype
Keys are any type
Can get size easily
WeakSets & WeakMaps
but...why?
WeakSet and WeakMap
- Have a subset of the methods/properties
- WS: Add, has, delete
- WM: Get, set, has, delete
- objects only!
- objects are weakly held
- free up memory!
- not enumerable (not iterable)
WeakMap example
var obj = getObjectFromLibrary();
function useObj(obj){
doSomethingWith(obj);
}
var map = new Map(); // maps can have object keys
function useObj(obj){
doSomethingWith(obj);
var called = map.get(obj) || 0;
called++; // called one more time
if(called > 10) report(); // Report called more than 10 times
map.set(obj, called);
}
var map = new WeakMap(); // create a weak map
function useObj(obj){
doSomethingWith(obj);
var called = map.get(obj) || 0;
called++; // called one more time
if(called > 10) report(); // Report called more than 10 times
map.set(obj, called);
}
Use Cases
- Set
- Any collection of unique values
- Map
- Versatile
- Dictionary-like collections, especially those that will be iterated over
- WeakSet
- 'branding' your classes?
- WeakMap
- storing metadata for an object
- prevent memory leaks
ES6 of the Week - 4 (maps & sets)
By beelai88
ES6 of the Week - 4 (maps & sets)
Maps and Sets / Weak maps and weak sets
- 612