ES6 Collections Using Map, Set, WeakMap, WeakSet - Lee-hyuna/33-js-concepts-kr GitHub Wiki
ES6 Collections: Using Map, Set, WeakMap, WeakSet
์๋ฌธ : https://www.sitepoint.com/es6-collections-map-set-weakmap-weakset/
**์ด ๊ธ์์๋ 4 ๊ฐ์ ์๋ก์ด ES6 ์ปฌ๋ ์ ๊ณผ ์ด๋ค์ด ์ ๊ณตํ๋ ์ฅ์ ์ ์ดํด ๋ด ๋๋ค. **
๋๋ถ๋ถ์ ์ฃผ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์๋ ์ฌ๋ฌ ์ ํ์ ๋ฐ์ดํฐ ์ปฌ๋ ์ ์ด ์์ต๋๋ค. ํ์ด์ฌ์๋ ๋ฆฌ์คํธ, ํํ ๋ฐ ๋์ ๋๋ฆฌ๊ฐ ์์ต๋๋ค. Java์๋ ๋ฆฌ์คํธ, ์ , ๋งต, ํ๊ฐ ์์ต๋๋ค. ๋ฃจ๋น์๋ ํด์์ ๋ฐฐ์ด์ด ์์ต๋๋ค. ์ง๊ธ๊น์ง ์๋ฐ์คํฌ๋ฆฝํธ์๋ ๋ฐฐ์ด ๋ง์์์ต๋๋ค. ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์๋ฐ์คํฌ๋ฆฝํธ์ ํต์ฌ์ด์์ต๋๋ค. ES6์๋ ์ธ์ด์ ํ๊ณผ ํํ๋ ฅ์ ์ถ๊ฐํ๋ 4 ๊ฐ์ง ์๋ก์ด ๋ฐ์ดํฐ ๊ตฌ์กฐ ์ธ ๋งต, ์ , ์ํฌ์ ๋ฐ ์ํฌ๋งต์ด ๋์ ๋์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ํด์๋งต ์ฐพ๊ธฐ
ํด์ ๋งต, ๋์ ๋๋ฆฌ ๋ฐ ํด์๋ ๋ค์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ํค / ๊ฐ ์์ ์ ์ฅํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด๋ฉฐ ์ด๋ฌํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋น ๋ฅธ ๊ฒ์์ ์ํด ์ต์ ํ๋ฉ๋๋ค.
ES5์์ ํค์ ๊ฐ์ ๊ฐ๋ ์์์ ์์ฑ ์ปฌ๋ ์ ์ธ JavaScript ๊ฐ์ฒด๋ ํด์๋ฅผ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ง๋ง [๊ฐ์ฒด๋ฅผ ํด์๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋ช ๊ฐ์ง ๋จ์ ](http://www.2ality.com/2012/01/objects -as-maps.html)์ ๊ฐ์ง๋ค.
๋จ์ #1: ES5์์ ํค๋ ๋ฌธ์์ด์ด์ด์ผ ํฉ๋๋ค.
JavaScript ๊ฐ์ฒด ์์ฑ ํค๋ ๋ฌธ์์ด์ด์ด์ผํ๋ฏ๋ก ๋ค์ํ ๋ฐ์ดํฐ ์ ํ์ ํค / ๊ฐ ์ ๋ชจ์์ผ๋ก ์ ๊ณต๋๋ ๊ธฐ๋ฅ์ด ์ ํ๋ฉ๋๋ค. ๋ฌผ๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ ์ ํ์ ๋ฌธ์์ด๋ก coerce/stringifyํ ์ ์์ง๋ง ์ถ๊ฐ ์์ ์ด ์ถ๊ฐ๋ฉ๋๋ค.
๋จ์ #2: ๊ฐ์ฒด๋ ๋ณธ์ง์ ์ผ๋ก ๋ฐ๋ณต์ด ๊ฐ๋ฅํ์ง ์์ต๋๋ค.
๊ฐ์ฒด๋ ์ปฌ๋ ์
์ผ๋ก ์ฌ์ฉํ๋๋ก ์ค๊ณ๋์ง ์์๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด์ ์์ฑ ์๋ฅผ ๊ฒฐ์ ํ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. (์๋ฅผ ๋ค์ด Object.keys is slow)๋ฅผ ์ฐธ์กฐํ์ญ์์ค. ๊ฐ์ฒด์ ์์ฑ์ ๋ฐ๋ณตํ๋ฉด ํ๋กํ ํ์
์์ฑ๋ ์ป์ ์ ์์ต๋๋ค. iterable ์์ฑ์ ๋ชจ๋ ๊ฐ์ฒด์ ์ถ๊ฐ ํ ์ ์์ง๋ง ๋ชจ๋ ๊ฐ์ฒด๊ฐ ์ปฌ๋ ์
์ผ๋ก ์ฌ์ฉ๋๋ ๊ฒ์ ์๋๋๋ค. forโฆ in
๋ฃจํ์ hasOwnProperty()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ์ด๋ ํด๊ฒฐ ๋ฐฉ๋ฒ ์ผ๋ฟ์
๋๋ค. ๊ฐ์ฒด์ ์์ฑ์ ๋ฐ๋ณต ํ ๋ ์์ฑ์ ์ฝ์
ํ ์์๋๋ก ๊ฒ์ ํ ํ์๋ ์์ต๋๋ค.
๋จ์ #3: ๋ด์ฅ๋ ๋ฉ์๋์ ์ถฉ๋์ด ์กด์ฌํฉ๋๋ค.
๊ฐ์ฒด์๋ constructor
, toString
๋ฐ valueOf
์ ๊ฐ์ ๋ด์ฅ ๋ฉ์๋๊ฐ ์์ต๋๋ค. ์ด๋ฌํ ์์ฑ ์ค ํ๋๊ฐ ์์ฑ์ผ๋ก ์ถ๊ฐ ๋ ๊ฒฝ์ฐ ์ถฉ๋์ด ๋ฐ์ํ ์ ์์ต๋๋ค. Object.create(null)
์ ์ฌ์ฉํ์ฌ (object.prototype์์ ์์๋์ง ์์) ๋ฒ ์ด(??) ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์์ง๋ง ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ ๋ฟ์
๋๋ค.
ES6์๋ ์๋ก์ด ์ปฌ๋ ์ ๋ฐ์ดํฐ ์ ํ์ด ํฌํจ๋์ด ์์ผ๋ฏ๋ก ๋ ์ด์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ณ ๋จ์ ์ ๊ทน๋ณต ํ ํ์๊ฐ ์์ต๋๋ค.
ES6์์์ ๋งต ์ปฌ๋ ์ ์ฌ์ฉ
๋งต
์ ์ฐ๋ฆฌ๊ฐ ์ดํด๋ณผ ์ฒซ ๋ฒ์งธ ๋ฐ์ดํฐ ๊ตฌ์กฐ / ์ปฌ๋ ์
์
๋๋ค. ๋งต์ ๋ชจ๋ ์ ํ์ ํค ๋ฐ ๊ฐ ๋ชจ์์
๋๋ค. ์ ๋งต๋ฅผ ์ฝ๊ฒ ๋ง๋ค๊ณ ๊ฐ์ ์ถ๊ฐ / ์ญ์ ํ๊ณ ํค / ๊ฐ์ ๋ฐ๋ณตํ์ฌ ํฌ๊ธฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค. ์ค์ํ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋งต ์์ฑ ๋ฐ ์ผ๋ฐ์ ์ธ ๋ฉ์๋์ ์ฌ์ฉ
const map = new Map();
map.set('hobby', 'cycling');
const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' };
const normalfoods = {};
map.set(normalfoods, foods);
for (const [key, value] of map) {
console.log(`${key} = ${value}`);
}
map.forEach((value, key) => {
console.log(`${key} = ${value}`);
}, map);
map.clear();
console.log(map.size === 0);
์ ์ปฌ๋ ์ ์ฌ์ฉ
์ ์ ์ค๋ณต์ด ํฌํจ๋์ง ์์ ์ ๋ ฌ ๋ ๊ฐ ๋ชฉ๋ก์ ๋๋ค. ๋ฐฐ์ด์ฒ๋ผ ์ธ๋ฑ์ฑ๋๋ ๋์ ํค๋ฅผ ์ฌ์ฉํ์ฌ ์งํฉ์ ์ ๊ทผํฉ๋๋ค. ์ธํธ๋ ์ด๋ฏธ Java, Ruby์ ์์ต๋๋ค. -2.3.0 / libdoc / set / rdoc / Set.html), Python ๋ฐ ๊ธฐํ ์ฌ๋ฌ ์ธ์ด๊ฐ ์์ต๋๋ค. ES6 ์ธํธ์ ๋ค๋ฅธ ์ธ์ด์์ ํ ๊ฐ์ง ์ฐจ์ด์ ์ ์์๊ฐ ES6์์ ์ค์ํ๋ค๋ ๊ฒ์ ๋๋ค (๋ค๋ฅธ ๋ง์ ์ธ์ด์์๋ ๊ทธ๋ ์ง ์์). ์ค์ํ Set ๋ฉ์๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const planetsOrderFromSun = new Set();
planetsOrderFromSun.add('Mercury');
planetsOrderFromSun.add('Venus').add('Earth').add('Mars');
console.log(planetsOrderFromSun.has('Earth'));
planetsOrderFromSun.delete('Mars');
console.log(planetsOrderFromSun.has('Mars'));
for (const planet of planetsOrderFromSun) {
console.log(planet);
}
console.log(planetsOrderFromSun.size);
planetsOrderFromSun.add('Venus');
console.log(planetsOrderFromSun.size);
planetsOrderFromSun.clear();
console.log(planetsOrderFromSun.size);
์ํฌ ์ปฌ๋ ์ , ๋ฉ๋ชจ๋ฆฌ, ๊ฐ๋น์ง ์ปฌ๋ ์
JavaScript ๊ฐ๋น์ง ์ฝ๋ ์ ์ ๋ ์ด์ ์ฐธ์กฐ๋์ง ์๋ ๊ฐ์ฒด๊ฐ ์๋์ผ๋ก ์ญ์ ๋๊ณ ์์์ด ์ฌ์๋๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์์์ ๋๋ค.
๊ฐ์ฒด์ ๋ํ ๋งต ๋ฐ ์ ์ ์ฐธ์กฐ๋ ๊ฐ๋ ฅํ๊ฒ ์ ์ง๋๋ฉฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ํ์ฉํ์ง ์์ต๋๋ค. DOM์์ ์ด๋ฏธ ์ ๊ฑฐ ๋ DOM ์์์ ๊ฐ์ด ๋ ์ด์ ํ์ํ์ง ์์ ํฐ ๊ฐ์ฒด๋ฅผ ๋งต / ์ ์ด ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ ๋น์ฉ์ด ๋ง์ด๋ค ์ ์์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ES6์๋ ์ํฌ๋งต
๊ณผ ์ํฌ์
์ด๋ผ๋ ๋ ๊ฐ์ ์๋ก์ด ์ํฌ ์ฝ๋ ์
์ด ๋์
๋์์ต๋๋ค. ์ด ES6 ์ฝ๋ ์
์ ๋ ์ด์ ํ์ํ์ง ์์ ๊ฐ์ฒด๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ์ง์ธ ์ ์๊ธฐ ๋๋ฌธ์ '์ํฌ' ์
๋๋ค.
์ํฌ๋งต
์ํฌ๋งต์ ์ฐ๋ฆฌ๊ฐ ๋ค๋ฃจ๊ณ ์๋ ์๋ก์ด ES6 ์ปฌ๋ ์ ์ค ์ธ ๋ฒ์งธ์ ๋๋ค. ์ํฌ๋งต์ ์ผ๋ฐ์ ์ธ ๋งต๊ณผ ์ ์ฌํ์ง๋ง ๊ฐ๋น์ง ์ฝ๋ ์ ๊ณผ ๊ด๋ จํ์ฌ ๋ฐฉ๋ฒ์ด ์ ๊ณ ์์ ์ธ๊ธ ํ ์ฐจ์ด์ ์ด ์์ต๋๋ค.
const aboutAuthor = new WeakMap();
const currentAge = {};
const currentCity = {};
aboutAuthor.set(currentAge, 30);
aboutAuthor.set(currentCity, 'Denver');
console.log(aboutAuthor.has(currentCity));
aboutAuthor.delete(currentAge);
์ฌ์ฉ ์ฌ๋ก
์ํฌ๋งต์ ๋ช ๊ฐ์ง ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ฌ๋ก๊ฐ ์์. ๊ฐ์ฒด์ private ๋ฐ์ดํฐ๋ฅผ private๋ก ์ ์งํ๊ณ DOM ๋ ธ๋ / ๊ฐ์ฒด๋ฅผ ์ถ์ ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Private ๋ฐ์ดํฐ ์ฌ์ฉ ์ฌ๋ก
JavaScript expert Nicholas C. Zakas ์์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. :
var Person = (function() {
var privateData = new WeakMap();
function Person(name) {
privateData.set(this, { name: name });
}
Person.prototype.getName = function() {
return privateData.get(this).name;
};
return Person;
}());
์ฌ๊ธฐ์์ '์ํฌ๋งต'์ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ private๋ก ์ ์งํ๋ ํ๋ก์ธ์ค๊ฐ ๊ฐ์ํ๋ฉ๋๋ค. Person
๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ ํ ์ ์์ง๋ง ํน์ Person
์ธ์คํด์ค๊ฐ ์์ผ๋ฉด privateDataWeakMap
์ ๋ํ ์ก์ธ์ค๊ฐ ํ์ฉ๋์ง ์์ต๋๋ค.
DOM ๋ ธ๋์์ ์ฌ์ฉ ์ฌ๋ก
Google Polymer ํ๋ก์ ํธ๋ PositionWalker๋ผ๋ ์ฝ๋์์`WeakMaps '๋ฅผ ์ฌ์ฉํฉ๋๋ค.
PositionWalker๋ DOM ํ์ ํธ๋ฆฌ ๋ด์ ์์น๋ฅผ ํ์ฌ ๋ ธ๋ ๋ฐ ํด๋น ๋ ธ๋ ๋ด์ ์คํ์ ์ผ๋ก ์ถ์ ํฉ๋๋ค.
์ํฌ๋งต์ ์ฌ์ฉํ์ฌ DOM ๋ ธ๋ ํธ์ง, ์ ๊ฑฐ ๋ฐ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํฉ๋๋ค.
_makeClone() {
this._containerClone = this.container.cloneNode(true);
this._cloneToNodes = new WeakMap();
this._nodesToClones = new WeakMap();
...
let n = this.container;
let c = this._containerClone;
// find the currentNode's clone
while (n !== null) {
if (n === this.currentNode) {
this._currentNodeClone = c;
}
this._cloneToNodes.set(c, n);
this._nodesToClones.set(n, c);
n = iterator.nextNode();
c = cloneIterator.nextNode();
}
}
์ํฌ์
์ํฌ์ ์ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๊ฐ ๋ ์ด์ ํ์ํ์ง ์์ ๋ ์์๋ฅผ ๊ฐ๋น์ง ์ปฌ๋ ์ ํ ์์๋ ์ธํธ ์ปฌ๋ ์ ์ ๋๋ค. ์ํฌ์ ์ ๋ฐ๋ณต์ ํ์ฉํ์ง ์์ต๋๋ค. ์ฌ์ฉ ์ฌ๋ก๋ ๋ค์ ์ ํ์ ์ ๋๋ค (ํ์ฌ๋ก์๋). ๋๋ถ๋ถ์ ์ผ๋ฆฌ ์ด๋ตํฐ๋ค์ ์ํฌ์ ์ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ํ๊ทธ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. (http://stackoverflow.com/questions/30556078/ecmascript-6-what-is-weakset-for). ES6-Features.org์๋ ์ํฌ์ ์์ ์์๋ฅผ ์ถ๊ฐ ๋ฐ ์ญ์ ํ๋ ์๊ฐ ์์ต๋๋ค. ๊ฐ์ฒด๊ฐ ํ์๋์๋์ง ์ฌ๋ถ๋ฅผ ์ถ์ ํฉ๋๋ค.
let isMarked = new WeakSet()
let attachedData = new WeakMap()
export class Node {
constructor (id) { this.id = id }
mark () { isMarked.add(this) }
unmark () { isMarked.delete(this) }
marked () { return isMarked.has(this) }
set data (data) { attachedData.set(this, data) }
get data () { return attachedData.get(this) }
}
let foo = new Node("foo")
JSON.stringify(foo) === '{"id":"foo"}'
foo.mark()
foo.data = "bar"
foo.data === "bar"
JSON.stringify(foo) === '{"id":"foo"}'
isMarked.has(foo) === true
attachedData.has(foo) === true
foo = null /* remove only reference to foo */
attachedData.has(foo) === false
isMarked.has(foo) === false
๋ชจ๋ ๊ฒ์ ๋งต์ผ๋ก ? ๋ ์ฝ๋ vs ES6 ์ปฌ๋ ์
๋งต ๋ฐ ์ ์ ํค / ๊ฐ ์์ ๋ฉ์ง ์ ES6์ ์ฝ๋ ์ ์ ๋๋ค. ์ฆ, ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด๋ ์ฌ๋ฌ ์ํฉ์์ ์ฌ์ ํ ์ปฌ๋ ์ ์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ํฉ์ด ์๊ตฌํ์ง ์๋ ํ ์๋ก์ด ES6 ๋ชจ์์ผ๋ก ๋ณ๊ฒฝ ํ ํ์๊ฐ ์์ต๋๋ค.
[MDN๋ฌธ์] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)์์๋ ์ธ์ ๊ฐ์ฒด ๋๋ ํค ์ปฌ๋ ์ ์ ์ฌ์ฉํ ์ง ์๋ ค์ค๋๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ๋ฐํ์๊น์ง ํค๋ฅผ ์ ์ ์์ผ๋ฉฐ ๋์ ์ผ๋ก ์ฐพ์์ผํฉ๋๊น?
- ๋ชจ๋ ๊ฐ์ ์ ํ์ด ๋์ผํ๊ณ ํธํ ๊ฐ๋ฅํฉ๋๊น?
- ๋ฌธ์์ด์ด ์๋ ํค๊ฐ ํ์ํฉ๋๊น?
- ํค-๊ฐ ์์ด ์ข ์ข ์ถ๊ฐ๋๊ฑฐ๋ ์ ๊ฑฐ๋ฉ๋๊น?
- ์์์ (์ฝ๊ฒ ๋ณ๊ฒฝ๋๋) ์์ ํค-๊ฐ ์์ด ์์ต๋๊น?
- ์ปฌ๋ ์ ์ด ๋ฐ๋ณต๋ฉ๋๊น?
์๋ก์ด ES6 ์ปฌ๋ ์ ์ผ๋ก ๋์ฑ ์ ์ฉํ ์๋ฐ ์คํฌ๋ฆฝํธ ์์ฑ
JavaScript ์ปฌ๋ ์ ์ ์ด์ ์๋ ์๋นํ ์ ํ๋์์ง๋ง ES6์์๋ ์์ ๋์์ต๋๋ค. ์ด ์๋ก์ด ES6 ์ปฌ๋ ์ ์ ์ธ์ด์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๊ณผ ์ ์ฐ์ฑ์ ์ ๊ณต ํ ๋ฟ๋ง ์๋๋ผ์ด๋ฅผ ์ฑํํ JavaScript ๊ฐ๋ฐ์์ ์์ ์ ๋จ์ํํฉ๋๋ค.
ํด๋น ๋ถ๋ถ์ ๋ํ ๋ฒ์ญ์ ๋ณธ๋ฌธ์ ๊ธ๊ณผ ์กฐ๊ธ ์์ดํ๊ฑฐ๋ ๋ถํ์ํ ๋ถ๋ถ์ด๋ผ ์๊ฐ์ด ๋์ด ์๋ต ํ์์ต๋๋ค. (์ด ๊ธ์ ๊ทผ์์ง์ ๊ด๋ จ๋ ๋ด์ฉ)