TIL coding
  • Initial page
  • 排版
  • Flexbox
  • Grid
  • jQuery
  • Untitled
  • JavaScript
    • An Introduction to JavaScript
    • Hello, world!
    • Code structure
    • The modern mode, "use strict"
    • Variables
    • Data types
    • Type Conversions
    • Operators
    • Comparisons
    • Interaction: alert, prompt, confirm
    • Conditional operators: if, '?'
    • Logical operators
    • Loops: while and for
    • The "switch" statement
    • Functions
    • Function expressions and arrows
    • JavaScript specials
    • Comments
    • Ninja code
    • Automated testing with mocha
    • Polyfills
    • Objects
    • Garbage collection
    • Symbol type
    • Object methods, "this"
    • Object to primitive conversion
    • Constructor, operator "new"
    • Methods of primitives
    • Numbers
    • Strings
    • Arrays
    • Array methods
    • Iterables
    • Map, Set, WeakMap and WeakSet
    • Object.keys, values, entries
    • Destructuring assignment
    • Date and time
    • JSON methods, toJSON
    • Recursion and stack
    • Rest parameters and spread operator
    • Closure
    • The old "var"
    • Global object
    • Function object, NFE
    • The "new Function" syntax
    • Scheduling: setTimeout and setInterval
    • Decorators and forwarding, call/apply
    • Function binding
    • Currying and partials
    • Arrow functions revisited
    • Property flags and descriptors
    • Property getters and setters
    • Prototypal inheritance
    • F.prototype
    • Native prototypes
    • Prototype methods, objects without __proto__
    • The “class” syntax
    • Class inheritance
    • Static properties and methods
    • Private and protected properties and methods
    • Extending built-in classes
    • Class checking: "instanceof"
    • Mixins
    • Error handling, "try..catch"
    • Custom errors, extending Error
    • Introduction: callbacks
    • Promise
    • Promises chaining
    • Error handling with promises
    • Promise API
  • Bootstrap
    • Navbar
Powered by GitBook
On this page
  • Map
  • Map from Object
  • Iteration over Map
  • Set
  • Iteration over Set
  • WeakMap and WeakSet

Was this helpful?

  1. JavaScript

Map, Set, WeakMap and WeakSet

現在已知有 object 儲存 key 的資料,array 儲存 index 的資料,但這對現實世界來說還不夠。

Map

map 跟 object 一樣,唯一不同的是 key 可以是任何類型的值。map 的方法如下:

  • new Map() – creates the map.

  • map.set(key, value) – stores the value by the key.

  • map.get(key) – returns the value by the key, undefined if key doesn’t exist in map.

  • map.has(key) – returns true if the key exists, false otherwise.

  • map.delete(key) – removes the value by the key.

  • map.clear() – clears the map

  • map.size – returns the current element count.

let map = new Map();

map.set('1', 'str1');   // a string key
map.set(1, 'num1');     // a numeric key
map.set(true, 'bool1'); // a boolean key

// remember the regular Object? it would convert keys to string
// Map keeps the type, so these two are different:
alert( map.get(1)   ); // 'num1'
alert( map.get('1') ); // 'str1'
alert( map.size ); // 3

// object key
let john = { name: "John" };
// for every user, let's store their visits count
let visitsCountMap = new Map();
// john is the key for the map
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123

// object with object key
let john = { name: "John" };
let visitsCountObj = {}; // try to use an object
visitsCountObj[john] = 123; // try to use john object as the key
// That's what got written!
alert( visitsCountObj["[object Object]"] ); // 123

// before map exist
// we add the id field
let john = { name: "John", id: 1 };
let visitsCounts = {};
// now store the value by id
visitsCounts[john.id] = 123;
alert( visitsCounts[john.id] ); // 123

// chain 
map.set('1', 'str1')
  .set(1, 'num1')
  .set(true, 'bool1');

Map from Object

// array of [key, value] pairs
let map = new Map([
  ['1',  'str1'],
  [1,    'num1'],
  [true, 'bool1']
]);

// Object.entries() returns [ ["name","John"], ["age", 30] ]
let map = new Map(Object.entries({
  name: "John",
  age: 30
}));

Iteration over Map

  • map.keys() – returns an iterable for keys,

  • map.values() – returns an iterable for values,

  • map.entries() – returns an iterable for entries [key, value], it’s used by default in for..of.

let recipeMap = new Map([
  ['cucumber', 500],
  ['tomatoes', 350],
  ['onion',    50]
]);

// iterate over keys (vegetables)
for (let vegetable of recipeMap.keys()) {
  alert(vegetable); // cucumber, tomatoes, onion
}

// iterate over values (amounts)
for (let amount of recipeMap.values()) {
  alert(amount); // 500, 350, 50
}

// iterate over [key, value] entries
for (let entry of recipeMap) { // the same as of recipeMap.entries()
  alert(entry); // cucumber,500 (and so on)
}

// map 有內建 forEach 方法
// runs the function for each (key, value) pair
recipeMap.forEach( (value, key, map) => {
  alert(`${key}: ${value}`); // cucumber: 500 etc
});

Set

set 是一個值的集合,裡面的值不能重複。替代方案是插入值時用 arr.find() 檢查是否有該值,但會造成性能變差。

  • new Set(iterable) – creates the set, and if an iterable object is provided (usually an array), copies values from it into the set.

  • set.add(value) – adds a value, returns the set itself.

  • set.delete(value) – removes the value, returns true if value existed at the moment of the call, otherwise false.

  • set.has(value) – returns true if the value exists in the set, otherwise false.

  • set.clear() – removes everything from the set.

  • set.size – is the elements count.

let set = new Set();

let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };

// visits, some users come multiple times
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);

// set keeps only unique values
alert( set.size ); // 3

for (let user of set) {
  alert(user.name); // John (then Pete and Mary)
}

Iteration over Set

  • set.keys() – returns an iterable object for values,

  • set.values() – same as set.keys, for compatibility with Map,

  • set.entries() – returns an iterable object for entries [value, value], exists for compatibility with Map.

let set = new Set(["oranges", "apples", "bananas"]);

for (let value of set) alert(value);

// the same with forEach:
set.forEach((value, valueAgain, set) => {
  alert(value);
});

WeakMap and WeakSet

WeakMap / WeakSet 不會阻止 JavaScript 清除 key 的記憶體。換句話說當 key 不存在,存在同個屬性的資料也會不見,使用在當物件存在的時候才需要的資料,物件消失資料也消失。

// delete object 
let john = { name: "John" };
// the object can be accessed, john is the reference to it
// overwrite the reference
john = null;
// the object will be removed from memory

// store in array object still exist
let john = { name: "John" };
let array = [ john ];
john = null; // overwrite the reference
// john is stored inside the array, so it won't be garbage-collected
// we can get it as array[0]

// store in map object still exict
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // overwrite the reference
// john is stored inside the map,
// we can get it by using map.keys()

// weakMap / weakSet 只能使用 object 當 key 值
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "ok"); // works fine (object key)
// can't use a string as the key
weakMap.set("test", "Whoops"); // Error, because "test" is not an object

// store in weakMap object desroty
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!

// 如果物件被移除,儲存值也會被移除
weakMap.set(john, "secret documents");
// if john dies, secret documents will be destroyed automatically

// 手動清理不要的物件
let john = { name: "John" };
// map: user => visits count
let visitsCountMap = new Map();
// john is the key for the map
visitsCountMap.set(john, 123);
// now john leaves us, we don't need him anymore
john = null;
// but it's still in the map, we need to clean it!
alert( visitsCountMap.size ); // 1
// and john is also in the memory, because Map uses it as the key

// weakMap 當物件消失值也會消失
let john = { name: "John" };
let visitsCountMap = new WeakMap();
visitsCountMap.set(john, 123);
// now john leaves us, we don't need him anymore
john = null;
// there are no references except WeakMap,
// so the object is removed both from the memory and from visitsCountMap automatically

// weakSet exaample
let messages = [
    {text: "Hello", from: "John"},
    {text: "How goes?", from: "John"},
    {text: "See you soon", from: "Alice"}
];
// fill it with array elements (3 items)
let unreadSet = new WeakSet(messages);
// use unreadSet to see whether a message is unread
alert(unreadSet.has(messages[1])); // true
// remove it from the set after reading
unreadSet.delete(messages[1]); // true
// and when we shift our messages history, the set is cleaned up automatically
messages.shift();
// no need to clean unreadSet, it now has 2 items
// (though technically we don't know for sure when the JS engine clears it)

weakMap 只有以下方法:

  • weakMap.get(key)

  • weakMap.set(key, value)

  • weakMap.delete(key)

  • weakMap.has(key)

weakSet

  • It is analogous to Set, but we may only add objects to WeakSet (not primitives).

  • An object exists in the set while it is reachable from somewhere else.

  • Like Set, it supports add, has and delete, but not size, keys() and no iterations.

PreviousIterablesNextObject.keys, values, entries

Last updated 5 years ago

Was this helpful?