2020-06-15

es6ds

ES6 Data Type

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

A summary of data type that introduced in ES6.

Type Symbol Map Set
Summary Unique ‘string’ Ordered ‘object’ whose key can be primitive & reference ‘Array’ with all unique value
Construct let sb = Symbol() let m = new Map([iteratble]) let s = new Set([iteratble])
Key-value Description as ‘key’
Symbol.keyFor(sb)
key=>any type ordered
value=>any type
key<=>value
unique key
Loop N\A For…of forEach() for…of forEach()
Transfer sb.toString() […m] = Array.from(m) <=> new Map(arr). […s] = Array.from(s) <=> new Set(arr).

Symbol

An unique ‘string’ that would never be equvlient to others

  • primitive data type

  • Symbol(< description >) function returns an anonymous, unique value

    1
    Symbol('foo') === Symbol('foo')  // false

    This functon has its static propertise and methods

    1
    2
    3
    4
    let sb = Symbol.for('foo')
    let sb2= Symbol.for('foo') //saved the value in global env in the memory
    sb ===sb2//true
    Symbol.keyFor(sb) //'foo'
  • Not new Symbol()

    1
    let sym = new Symbol()  // TypeError
    1
    2
    3
    4
    let sym = Symbol('foo')
    typeof sym // "symbol"
    let symObj = Object(sym)
    typeof symObj // "object"

    But it has instance/prototype properties and methods

    1
    2
    3
    Symbol.prototype.toString()
    let sb = Symbol('context');
    console.log(sb.description); //context

    Returns a string containing the description of the Symbol. Overrides the Object.prototype.toString() method.

Use cases

To dealing with the same string name, use symbol to create unique value;

1
2
3
4
5
6
7
8
9
10
11
let user1= {
name:'Jack'
}
let user2 = {
name:'Jack'
}
let data = {
[user1]:{age:19},
[user2]:{age:22}
}
console.log(data[user1]) //{age: 22}

Using symbol:

1
2
3
4
5
6
7
8
9
10
11
12
13
let user1= {
name:'Jack',
key:Symbol()
}
let user2 = {
name:'Jack',
key:Symbol()
}
let data = {
[user1.key]:{age:19},
[user2.key]:{age:22}
}
console.log(data[user1.key]) //{age: 19}

for...in can only get the propertise of an object that its key is not a symbol.

The Object.getOwnPropertySymbols() method can only get the symbol peroproty

1
2
3
4
5
6
7
8
let sb = Symbol('b')
let obj = {
a:'a',
[sb]:'symbol'
}
for(let item of Reflect.ownKeys(obj)){
console.log(item)
}

The symbol can protect the propertise to be looped from outside.

Map

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

An order object whose key can be any data type

  • iterable, can be looped through for...of
  • Its size can be easily obtained by the size property
  • use new Map([iterable]) to create a Map object where the key-value of each iterable were pushed into the Map
  • Use Map.prototype.set([key]) to push a new value, use .get([key])to get the value
  • Map.prototype.has() return boolean
  • The key has to be unique. No repeating keys. The later insertion would overwrite the earlier one.
1
2
3
4
5
6
7
8
let obj={a:'a'}
let obj1={b:'b'}
let m = new Map([[obj,'user'],[function foo(){},'function']])
console.log(m)//Map(2) {{…} => "user", ƒ => "function"}
m.set(obj1,'b')
m.get(obj1)//'b'
m.get({b:'b'})//undefined
m.has(obj)//ture
  • These methods return a new iterator object contains each key/value/entry in the map
1
2
3
4
5
[...m] // [[{},'user'],[f,'function'],[{...},'b']]
m.keys() //MapIterator {{…}, ƒ, Array(2)}
[...m.keys() ] // [{…}, ƒ, Array(2)]
m.values()
m.entires()
  • Map.prototype.forEach(callbackFn[, thisArg]) can loop the map
1
2
3
4
5
6
7
8
9
m.forEach((value)=>{
console.log(value);
})
m.forEach((value,key)=>{
console.log(value,key);
})
for (let item of m){
cosnole.log(item);
}

Compared with object

  • An Object has a prototype, so there are default keys in the map.
  • (This can be bypassed using map = Object.create(null).)
  • The keys of an Object are Strings or Symbols, where they can be of any value for a Map.

Use case

use as an advanced version of object (hash map) to store. eg. Store the DOM element as the keys;

1
2
3
4
5
6
7
8
<body>
<div name='first' data-index='1'>
aaaa
</div>
<div name='second' data-index='2'>
bbbb
</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
let map =new Map();
docment.querySelectorAll('div').forEach(item=>{
map.set(item,{
name:item.getAttribute('name'),
index:item.dataset.index
})
})
map //div=>{} div=>{}
map.forEach((config,ele)=>{
ele.addEventListener('click'()=>{
alert(config.name +'at' + config.index)
})
})
1
2
3
4
5
I accept aggreement:
<input type="checkbox" name="agreement" error="please accept" />
I am Student:
<input type="checkbox" name="student" error="only open to student" />
<input type="submit" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function post() {
let map = new Map();
let inputs = document.querySelectorAll('[error]');
inputs.forEach((item) => {
map.set(item, {
error: item.getAttribute('error'),
status: item.checked,
});
});
// console.log([...map]);
return [...map].every(([elem, config]) => {
config.status || alert(config.error);
return config.status;
});
}

Weak Map

The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced. The keys must be objects and the values can be arbitrary values.

  • Similar API with Map
  • WeakMap keys are not enumerable (i.e., there is no method giving you a list of the keys). If they were, the list would depend on the state of garbage collection, introducing non-determinism.
  • they are a target of garbage collection (GC) if there is no other reference to the object anymore.
1
2
3
4
5
6
let wm = new WeakMap()
let obj={a:'a'}
wm.set(obj,1)
wm.keys()//TypeError: wm.keys is not a function
wm.values()//❌
wm.entries()//❌

Use case

to store private data for an object, or to hide implementation details.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const privates = new WeakMap();

function Public() {
const me = {
// Private data goes here
};
privates.set(this, me);
}

Public.prototype.method = function () {
const me = privates.get(this);
// Do stuff with private data in `me`...
};

module.exports = Public;

Set

The Set object lets you store unique values of any type, whether primitive values or object references.

  • ‘unique’: NaN and undefined can also be stored in a Set.
  • All NaN values are equated (i.e. NaN is considered the same as NaN, even though NaN !== NaN).
1
2
3
4
5
6
7
8
let set = new Set(['a',2])
set.size//2
set.add({obj:'obj'})
set.has('b')//false
set.delete('a')//return true
set// Set(1) {2}
set.delete('b')//false
set.clear()

Loop:

iterator: since set only has keys so the set.values() return the keys as well. the entries() returns [[keys:keys]]

1
2
3
4
5
6
7
8
9
10
11
12
13
set.keys()
set.values()
set.entries()
set.forEach(((item)=>{
console.log(item)
}))

let isSuperSet = (subSet,superSet)=>{
let(item of subSet){
!superSet.has(item) return false
}
return true;
}

string type can also be transfered

1
2
3
let text = 'India';
let mySet = new Set(text); // Set {'I', 'n', 'd', 'i', 'a'}
mySet.size; // 5
1
2
let set= new Set('17323845');
set = new Set([...set].filter(num=>num<5))//Set(4) {"1", "3", "2", "4"

Use case

  • remove duplicate from an array
1
2
3
4
5
6
let arr=[1, 2, 3, 2, 'b', 1, 'b']
let set = new Set(arr);
arr=Array.from(set)
arr= [...set]
//or in one line:
arr = [... new Set(arr)]
  • borrow API from Array
1
2
let intersection = new Set([...set1].filter(x => set2.has(x)));
let difference = new Set([...set1].filter(x=>!set2.has(x)))

Search history

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 let obj = {
data: new Set(),
keyword(word) {
this.data.add(word);
},
show() {
let ul = document.querySelector('ul');
ul.innerHTML = '';
this.data.forEach((value)=> {
ul.innerHTML += `<li>${value}</li>`;
});
}
};
let input = document.querySelector("[name='hd']");
input.addEventListener('blur', function () {
obj.keyword(this.value);
obj.show();
}

WeakSet

WeakSet objects are collections of objects. All objects in a WeakSet’s collection are unique.

Key difference with set:

  • WeakSets are collections of objects only.
  • WeakSets are not enumerable.
1
2
3
4
5
6
7
8
9
var ws = new WeakSet();
var foo = {};//has to be an object
var bar = {};

ws.add(foo);
ws.add(bar);

ws.has(foo); // true
ws.has(bar); // true

Use case

Store DOM element, if the element was deleted from the DOM, the weakset lost the reference as well. No wasting memory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<li>houdunren.com <a href="javascript:;">x</a></li>
<li>hdcms.com <a href="javascript:;">x</a></li>
<li>houdunwang.com <a href="javascript:;">x</a></li>
</body>
<style>
.remove {
border: solid 2px #eee;
opacity: 0.8;
color: #eee;
}
.remove a {
background: #eee;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Todo {
constructor() {
this.items = document.querySelectorAll('ul>li');
this.lists = new WeakSet();
this.items.forEach((item) => this.lists.add(item));
}
run() {
this.addEvent();
}
addEvent() {
this.items.forEach((item) => {
let a = item.querySelector('a');
a.addEventListener('click', (event) => {
const parentElement = event.target.parentElement;
if (this.lists.has(parentElement)) {
parentElement.classList.add('remove');
this.lists.delete(parentElement);
} else {
parentElement.classList.remove('remove');
this.lists.add(parentElement);
}
});
});
}
}
new Todo().run();