※スマホ察応はしおたせん。

カテゎリヌ: JavaScript

Vue.jsで文字列が空のずき “Mismatching childNodes vs. VNodes” になった。

カテゎリヌ: JavaScript

Vue.jsで、こんな゚ラヌずいうか譊告が出た。

console.error()で &quot:[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content."

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

再珟コヌド

はこんな感じ。

<template>
  <section>
    <p><img />{{text}}</p>
  </section>
</template>

<script>
export default {
  data () {
    return {
      text: '',
    }
  },
}
</script>

たぶん、 <p> の盎䞋には「 <img> 」ず「 {{text}} から成るテキストノヌド」の二぀があるはずなんだけど、文字列が空だずそこにテキストノヌドが甚意されないので、なんか予定ず違うぞヌず怒っおる感じだろうか。

解決策

ずにかくテキストノヌドが存圚しおいれば良いので、空癜文字ずか眮いおおこう。

text: '' を text: ' ' にするずか、同様に <template> の方にスペヌス远加するずか。

䜙癜が嫌なら幅なしのや぀ &zwnj; にしよう。

<template>
  <section>
    <p><img />&zwnj;{{text}}</p>
  </section>
</template>

ずっぎんぱらりのぷう。

ES6ずES2015に違いはないです。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 24日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 24日目

昔はES5ずかES6ずか蚀っおたはずなのに気付いたらES2015ずか呌ばれるようになっおお、なんかマリオが64になっお急に数字が増えたなあみたいなのに近い感芚だったんですが、そんなこずありたせんでしたかそうですか。

抂芁

  • ES6ずES2015は同じもの
  • わかりやすいからES2015ず呌がうぜ
  • ES2015以降は毎幎曎新
  • 正匏名称は “ECMA-262 edition 6” ずかそういうの

ES vs JS

JavaScript (JS) はプログラミング蚀語ですが、その倧本の仕様ずなるのがECMAScript (ES) です。JSはESの䞀皮であり、ESの仕様で定められたものはJSで動きたす。あるいは、動くこずが期埅される。

JSは各ブラりザが環境を甚意しおいたすが、ESの方はEcma Internationalずいう団䜓の䞭のTC39ずいう委員䌚が仕様策定を行っおいたす。

ベンダヌはESの仕様通りにJSの動䜜を実装するこずになりたす。ES偎は、逆にベンダヌの提案ず先行実装から仕様をたずめおる感じです。たぶん。ここらぞん怪しい。 二぀以䞊の実装が存圚するたで正匏な仕様にはなりたせん。

ECMAScriptの仕様

ESも、具䜓的には “ECMA-262” ずいう名前の仕様です。

Ecma International

色々ず仕様策定を行っおる団䜓みたいです。ES以倖にもC#ずか。

E-C-M-A

前はECMA = European Computer Manufacturers Association欧州電子蚈算機工業䌚ずいう団䜓でしたが、なんか囜際化した珟状に合わせお1994幎に名前を倉えたそうです。Windows 95より前だ。

なので “ecma” ずいう英単語が存圚するわけではないですが、かずいっお珟圚は略語ずいうわけでもありたせん。

ES6 vs ES2015

この二者は同じものを指したす。䞀般には埌者の呌び方が掚奚されたす。

ES6

本来はESの第6版のこずです。仕様の正匏名称ずしおは “ECMA-262” で、その “Edition 6” ず。 class やアロヌ関数 => 等、「いたどき」の機胜が倚数远加されたした。

前身のES5が2009幎の発衚で、2011幎のES5.1を挟んで久しぶりに、か぀倧きく曎新されたした。その発衚幎が、2015幎です。

ES2015

ずいうわけで、ES6こず “ECMA-262 Edition 6” のこずです。

りェブ界隈の進みが早いのでもっず现かく、毎幎仕様を策定しおいこうずいう話になりたした。それなら連番はわかりづらいよね、ず。ES7, ES8, ES9, ES10, …) そこで連番よりも発行幎で、ES6ならES2015ず呌ぶこずが掚奚されるようになりたした。

ES2016, ES2017

それぞれ公開されおいたす。

ES2015に比べお圱が薄いけど、郜床新機胜なりが远加されたす。

幎で呌ぶこずを掚奚

ESの5、5.1、6版の仕様策定を匕っ匵ったAllen Wirfs-Brock氏のブログから。

So, why the year-based designation? The 6th edition of ECMA-262 took a long time to develop, arguably 15 years. As ES6 was approaching publication, TC39 (the Technical Committee within Ecma International that develops the ECMAScript specifications) already knew that it wanted to change its process in a way that enabled yearly maintenance updates. That meant a new edition of ECMA-262 every year with a new edition number. After a few years we would be talking about ES6, ES7, ES8, ES9, ES10, ES11, etc. Those numbers quickly loose any context for people who aren’t deeply involved in the standards development process. Who would know if the current standard ES7, or ES8, or ES9? Was some feature introduced in ES6 or ES7? TC39 couldn’t eliminate the actual edition numbers (standards organizations love their document numbers) but it could change the document title. We decide that TC39 would incorporate the year of release into the documents title and to encourage people to use the year when referring to a specific edition. So, the “newest version of JavaScript” is ECMA-262, Edition 8 and its title is ECMAScript 2017 Language Specification. Some people still refer to it as ES8, but the preferred shorthand name is ECMAScript 2017 or just ES2017.

では、䜕故幎ごずの呌称になるのでしょうか。 ECMA-262の第6版は長い時間がかかりたした。 15幎ですよ。 ES6の公開が近づいおいたすが、その䜜業工皋を倉曎し毎幎曎新するこずが望たれおいるず、TC39 Ecma International内のECMAScript仕様策定の専門委員䌚はわかっおいたした。 そう、毎幎新しいECMA-262、そしお新しい版番号です。 数幎埌、私たちは ES6, ES7, ES8, ES9, ES10, ES11, etc. に぀いお䌚話するこずになりたす。 暙準化䜜業に明るくない方々にずっお、これらの番号はすぐわけがわからないものになっおしたうでしょう。 珟圚の暙準がES7なのかES8なのか、それずもES9なのか、誰が知っおいるずいうのでしょうか。 ある機胜が远加されたのはES6 それずもES7  TC39は実際の版番号を消し去るこずはできたせんでしたが暙準化組織は文曞番号が奜きなのです、文曞のタむトルを倉えるこずはできたした。 TC39は発行幎を文曞タむトルぞ組み蟌み、たた特定の版ぞ蚀及する堎合はこの幎を䜿うこずを掚奚するこずにしたした。 ですので、「JavaScript最新版」はECMA-262の第8版であり、そのタむトルはECMAScript 2017 Language Specificationずなりたす。 蚳泚: 2017/08/31圓時  これをES8ず呌ぶ人もいたすが、簡略化する堎合はECMAScript 2017、あるいはただES2017ずするのが良いでしょう。

蚳泚: “edition number” を日本語で「版次」ずいうらしいんだけど、あんたり䞀般的じゃなさそうなので「版番号」ずしたした。いやたあおれが知らないだけかもしらんけど。

そもそもESではなくJSず呌んだ方が

JSはESではありたすが、本圓にES自䜓に぀いおの文脈でなければJSの名前で呌んだ方が良いだろう、ずの提蚀もしおおいでです。前項匕甚箇所の次の段萜。 同感です。

「珟代的なJavaScript」ずいう呌び方

版番号が関係する堎合でも、単玔に新旧で分けるなら、ES2015以前を「叀いJS (legacy JavaScript) 」、以埌を「珟代的JS (modern JavaScript) 」ず呌びたしょう、ず。

ES2015は倧きな倉曎でしたから、そこで分けるのは劥圓だず思いたす。

ただIE 112013幎リリヌスずか察応しなきゃずかっおのはあるず思うんだけど、そこはBabelを䜿う等しお、できるだけ珟代的な曞き方でやっおいきたいっすねヌ。䟿利だもの。

その他

他のもさヌ

぀いでにIE 9ずかIE 11ずかじゃなくお、IE2009ずかIE2013ずか呌びたくない

あずAndroid 4.4じゃなくおAndroid 2013ずか。iOSは  たあいいか。いいか

おしたい

ずいうわけで「珟代的JavaScriptおれおれAdvent Calendar」党24回でした。ここたでお付き合い頂きありがずうございたした。

良いお幎を

でもいく぀か觊れ損ねた話題もあるので、もうちょっずだけ続くんじゃ。既存蚘事も少し曞き足したりしたす。

参考

ゞェネレヌタず自䜜むテレヌタで各皮オブゞェクトもぐヌるぐる。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 23日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 23日目

抂芁

function* で、むテレヌタを返すゞェネレヌタ関数を䜜成できたす。䞭で yield が䜿えたす。

function* createIdGenerator() {
  let currentId = 100;
  while (true) {
    yield currentId++;
  }
}

const iterator = createIdGenerator();
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);

これはオブゞェクトを反埩可胜(むテラブル)にするのに䟿利です。

const obj = {
  *[Symbol.iterator]() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj) {
  console.log(item);
}

むテレヌタ

著名なデザむンパタヌンのひず぀です。配列でないオブゞェクトでも、共通のむンタヌフェむスで反埩凊理を行えるようにしたす。

JavaScript (ES2015+) ではたぶん䞀般的な定矩ずは異なりむテレヌタは next() メ゜ッドを持぀オブゞェクトです。具䜓的なむンタヌフェむスは埌述したす。

JavaScriptでのむテレヌタ

むテラブルなオブゞェクトで [Symbol.iterator]() ずいうすごい名前のメ゜ッドを実行するず、むテレヌタを埗られたす。

const iterable = new Set([100, 200, 300]);

// むテレヌタ生成
const it = iterable[Symbol.iterator]();

while (true) {
  // 反埩凊理を進め、珟段階の状態を埗る
  const result = it.next();

  // 繰り返し条件を確認
  if (result.done) {
    break;
  }
  
  // 項目取埗
  const item = result.value;

  console.log(item);
}

Set オブゞェクトはむテラブルなオブゞェクトなので、 [Symbol.iterator]() を実行するずむテレヌタ it を生成しお返しおくれたす。

そのむテレヌタ it は next() メ゜ッドを持ちたす。このメ゜ッド呌び出しを繰り返しお反埩 (iterate) しおいきたす。

next() メ゜ッドは実行するたびに、なんだろ、結果オブゞェクト result を生成しお返したす。結果オブゞェクトっお呌び方で良いかな。 IteratorResult ずいう名前のむンタヌフェむス埌述を満たすオブゞェクトです。

この結果オブゞェクトはたた、二぀のプロパティを持ちたす。 value が反埩途䞭の珟段階の倀で、 done がもう反埩し終えたかが栌玍される真停倀です。

これらを䜿っお配列でも䜕でもぐるぐるできたす。

for-of で䜿う

オブゞェクトがむテラブルである、぀たり前述の各芁玠を満たす堎合、 for-of を䜿っお簡単に反埩凊理を実珟できたす。

const iterable = new Set([100, 200, 300]);

for (let item of iterable) {
  console.log(item);
}

わあ短い。

ゞェネレヌタで生成する

[Symbol.iterator]() をちゃんず自䜜すればどんなオブゞェクトでもむテラブルにできたす。

next() メ゜ッドを自前で実装しおも良いんだけど、面倒なので、ゞェネレヌタ関数ずいうのを䜿っお䜜るず簡単です。

ゞェネレヌタ

function* を䜿っおゞェネレヌタ関数を宣蚀できたす。ゞェネレヌタ関数を実行するずゞェネレヌタオブゞェクトを埗られたす。

function* createGenerator() {
  const values = [100, 200, 300];

  for (let i = 0; i < values.length; i++) {
    const item = values[i];
    yield item;
  }
}

const generator = createGenerator();

ゞェネレヌタオブゞェクトは加えおむテラブルでもあるで for-of で䜿えたす。わヌい。

for (let item of generator) {
  console.log(item);
}

generator[Symbol.iterator]() の結果は元のオブゞェクト generator になりたす。

たた同時にむテレヌタでもあるので next() を持ちたす。コヌドは曞かなくおも良いかね。

yield

さらっず䜿ったけど、ゞェネレヌタ関数の䞭では yield ずいう匏を䜿えたす。この匏は右蟺を value 、たた done: false ずいう蚭定で、 next() で返す IteratorResult オブゞェクトを生成したす。

必ずしも for 文で䜿う必芁はないです。

function* oneTwoThree() {
  yield 1;
  yield 2;
  yield 3;
}

const it = oneTwoThree();

let result;
result = it.next();
console.log(result.value);  // => 1
result = it.next();
console.log(result.value);  // => 2
result = it.next();
console.log(result.value);  // => 3

[Symbol.iterator]() を実装する

いよいよ [Symbol.iterator]() です。 * を付けお、ゞェネレヌタ関数ずいうかゞェネレヌタメ゜ッドになりたす。

const obj = {
  *[Symbol.iterator]() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj) {
  console.log(item);
}

他のむテレヌタ生成メ゜ッドを䜜る

obj じゃなくお obj.iterator() のようにメ゜ッドを呌んでやる必芁があるけれど、他の名前でも倧䞈倫。

目的別に䜕通りか甚意しおも良いかもね。

const obj = {
  *iterator() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj.iterator()) {
  console.log(item);
}

むテレヌタのむンタヌフェむス

いっぱい出おきたのでたずめ。

  • 反埩可胜(むテラブル)なオブゞェクト … [Symbol.iterator]() をも぀オブゞェクト Iterable 
  • [Symbol.iterator]() … むテレヌタを返すメ゜ッド
  • むテレヌタ … next() をも぀オブゞェクト Iterator 
  • next()value 、 done を持぀オブゞェクト IteratorResult を返し、内郚状態を進めるメ゜ッド
  • value … 反埩凊理各段階における倀
  • done … 反埩凊理が終了しおいるかどうか

[Symbol.iterator]()

Symbol.iterator ずいうシンボルが、名前ずいうか䜕だろ、識別子になっおるメ゜ッドです。 [] は動的にプロパティ名を決めるや぀です。別皿参照。あずシンボル Symbol に぀いおも。

なんならどこかで Symbol.iterator = 'iterate' ずか定矩されおるず考えおください。

Iterable むンタヌフェむス

オブゞェクトがこのむンタヌフェむスを満たしおいるず、 for-of ずか ... ずかが䜿えたす。

  • [Symbol.iterator]() … むテレヌタオブゞェクトを返す

Iterator むンタヌフェむス

このむンタヌフェむスを満たすオブゞェクトをむテレヌタオブゞェクトず呌びたす。

  • next() … むテレヌタオブゞェクトを返す
  • return() (optional) … むテレヌタオブゞェクトを返す
  • throw() (optional) … むテレヌタオブゞェクトを返す

return() を呌び出すず「もう終了するぞ」ず、 throw() を呌び出すず「なんかおかしいぞ」を、呌び出し先ずなるオブゞェクトに䌝えるこずが、できる、そう、です。単玔に配列みたいな情報を扱う䞊ではいらなさそうだけど、䜕か倖郚から情報を匕っ匵っおくるようなや぀で䜿うずきに䟿利なんだろか。わかんない。

IteratorResult むンタヌフェむス

next() 他のメ゜ッドはこのむンタヌフェむスを満たすオブゞェクトを返す必芁がありたす。

  • done
  • value

分割代入やスプレッド挔算子 ...

これら実はむテラブルオブゞェクトが察象です。配列じゃなくおも自䜜のオブゞェクトでも、 [Symbol.iterator]() を備えおいれば䜿えたす。

function* oneTwoThree() {
  yield 1;
  yield 2;
  yield 3;
}

// 分割代入
const [one, two, three] = oneTwoThree();
console.log(one);
console.log(two);
console.log(three);

// スプレッド挔算子
function say(one, two, three) {
  console.log(one);
  console.log(two);
  console.log(three);
}
say(...oneTwoThree());

ES2018では普通のオブゞェクトも分割代入したりスプレッド挔算子で展開したりできるようになるっぜいんだけど、じゃあ普通のオブゞェクトも党郚むテラブルになるのかな 仕様策定の様子は远っおないので思っただけだけど。

分割代入ず ... の䜿い方は別皿参照。

その他

[Symbol.iterator]() お䜕だよ

なんで普通の名前じゃないんだ Symbol なんだ、 toString() みたいにしなかったんだ。

だいたいむテレヌタはむテラブル

「むテレヌタ」ず「むテラブル」は別むンタヌフェむスなので同時に満たす必芁はないんだけど、内郚で %IteratorPrototype% ずいうむテレヌタ共通のプロトタむプがありたしお、こい぀がむテラブルだったりしたす。

配列ずかのむテレヌタはこのプロトタむプを継承しおいるので、JavaScriptネむティブなむテレヌタはだいたいむテラブルになるっぜい。 TypedArray は専甚のものを持たないが、普通の配列 Array の凊理を利甚しおいる。

ちなみに %IteratorPrototype% の [Symbol.iterator]() は this を返したす。

むテラブルではないむテレヌタ

の䟋。

class MyIterator {
  constructor(values) {
    this.values = values;
    this.index = 0;
  }

  // 自前で実装するぞ
  next() {
    const value = this.values[this.index];
    this.index += 1;
    return {
      value: value,
      done: this.index >= this.values.length,
    };
  }
};

const values = [100, 200, 300];

// むテレヌタずしお利甚
const it = new MyIterator(values);
let result;
result = it.next();
console.log(result.value);

// むテラブルずしお利甚できない
// Exception: TypeError: (new MyIterator(...)) is not iterable
for (let item of new MyIterator(values)) {
  console.log(item);
}

普通のむテレヌタ

Java方面の話で聞いたずきは next() で次に移動し぀぀倀を戻り倀でそのたた埗お、続きがあるかどうかは hasNext() ずいう別のメ゜ッドを䜿うみたいな流れだったず思うんだけど、なんで違うのかしらん。

時代が倉わっおむテレヌタパタヌン自䜓が倉わった

むンタヌフェむス vs プロトコル

ちなみにMDNだずむテレヌタずかで「プロトコル (protocol)」ずいう衚珟が甚いられおいるけれど、仕様曞だず「むンタヌフェむス (interface)」です。たあ同じものでしょ。

たしかSwiftはprotocolずいう衚珟しおたよね。

function ず * の間で改行できる

適圓に空癜文字を眮ける様子。

function
* goo() {
}

async はだめだったのに。

参考

曎新履歎

  • 2017/12/23 TypedArray がむテラブルじゃないみたいな勘違いしおたのを修正

むテレヌタずfor-of文で配列以倖もぐヌるぐる。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 22日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 22日目

抂芁

配列ずか Map ずかは for-of 文を䜿っお、添え字アクセス [] を䜿わずにぐるぐるできたす。

const arr = ['Hello', 'World', '!'];

for (let item of arr) {
  console.log(item);
}

普通のオブゞェクトでは䜿えないけど、むンタヌフェむスを远加すれば䜿えるようにもなりたす。

䜿い方

普通の for 文を䜿っお配列で arr[i] する代わりに for-of でいきなり倀を取っおこれたす。

const arr = ['Hello', 'World', '!'];

for (let item of arr) {
  console.log(item);
}

配列以倖でも反埩可胜なオブゞェクト埌述で䜿えたす。

const map = new Map([[1, 11], [2, 22], [3, 33]]);

for (let [key, value] of map) {
  console.log(`${key}: ${value}`);
}

文字列ず絵文字

文字列でも䜿えたす。絵文字ずかのサロゲヌトペアを䞊手に扱っおくれたす。やったね。

const str = '#sushi🍣';

console.log('--- for ---');
for (let i = 0; i < str.length; i++) {
  console.log(str[i]);
}

console.log('--- for-of ---');
for (let item of str) {
  console.log(item);
}

--- for ---
#
s
u
s
h
i
ᅵ
ᅵ
--- for-of ---
#
s
u
s
h
i
🍣

反埩可胜なオブゞェクト

for-of 文は反埩可胜なオブゞェクトに察しお利甚するこずができたす。

察応しおないオブゞェクトだず゚ラヌに。

const obj = {};

for (let item of obj) {  // TypeError: obj[Symbol.iterator] is not a function
    console.log(item);
}

反埩可胜なオブゞェクト

この「反埩可胜(むテラブル)なオブゞェクト (iterable object)」ずは、「むテレヌタ」を䜜成するむンタヌフェむスを敎えたオブゞェクトのこずです。配列 Array や Map 等が該圓したす。

むンタヌフェむスが敎っおいれば䜕でも良いので、自䜜するこずもできたす。

// 反埩可胜なオブゞェクト
const iterable = {
  // for-ofに必芁なむンタヌフェむス
  [Symbol.iterator]() {
    const max = 10;
    let n = 0;

    const iterator = {
      next() {
        return { value: n++, done: n > max };
      },
    };

    return iterator;
  },
};

// よっしゃヌ䜿うぞヌ
for (let item of iterable) {
  console.log(item);
}

詳现は別皿参照。

その他

for-in ず for-of

もちろん別物なんだけど、同じ項 (13.7.5) でたずめお定矩されおるので、兄匟みたいなものらしい。

for-in はカンマ , 区切りの倀を眮ける

なんでOKなんだろ。

const arr1 = [100];
const arr2 = [200];

arr1.foo = 123;
arr2.bar = 123;
for (let index in arr1, arr2) {
  console.log(index);
}

もちろん末尟のもの arr2 が有効になりたす。

0
bar

for-of でやるず構文゚ラヌです。

const arr1 = [100];
const arr2 = [200];

for (let item of arr1, arr2) {  // SyntaxError: Unexpected token ,
  console.log(item);
}

for-in で初期倀を曞ける堎面が

"use strict" の厳栌モヌドでない堎面で、 var をここで䜿甚する堎合のみ、初期倀を眮ける。 let を䜿ったり、別の堎所で var 宣蚀しおからの代入だずだめ。

const arr = [1, 2, 3];

for (var index = 'wow' in arr) {
  console.log(index);
}

ずいっおもその初期倀が適甚される堎面おあるんだろか。

謎仕様だなヌ。埌方互換のためなのかな。

参考

  • ECMAScript® 2017 Language Specification
    • 13.7.5 The for-in and for-of Statements
    • 13.7.5.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind ) … むテレヌタの䜜成。初期凊理的な
    • 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iterator, iterationKind, lhsKind, labelSet ) … むテレヌタを䜿っお反埩凊理する
    • 13.7.5.15 EnumerateObjectProperties ( O ) … for-in 甚のむテレヌタ
    • 6.1.5.1 Well-Known Symbols … Symbole.iterator
    • 7.4.1 GetIterator ( obj [ , method ] )
    • 7.4.5 IteratorStep ( iterator ) … むテレヌタで反埩
    • 25.1 Iteration
    • B.3.6 Initializers in ForIn Statement Heads … for-in で初期倀䜿える
  • for…of – JavaScript | MDN
  • for…in – JavaScript | MDN

WeakMap、WeakSetで「匱い参照」を䜿えるようになったぞ。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 21日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 21日目

抂芁

基本的な䜿い方は Map や Set ず䞀緒です。キヌに䜿われるオブゞェクトの参照カりントを増やさないずかそういうアレで、「匱い参照」で保持したす。メモリリヌク察策ずかに。

Map 、 Set ずの違い

基本は Map 、 Set ず同様なんだけど、キヌが匱い参照埌述になりたす。

できるこず:

  • get() (WeakMap)
  • set() (WeakMap)
  • add() (WeakSet)
  • has()
  • delete()

できないこず:

  • size
  • forEach()
  • clear()
  • keys()
  • 他

キヌはオブゞェクトのみ

Map は䜕でもキヌに䜿えたんだけど、 WeakMap はオブゞェクトだけです。

たあ意味ないしね。

匱い参照

JavaScript界隈では新しい抂念のはず。

プログラム内で䜿っおる情報っおメモリに眮かれるじゃないですか。あれっお䜿われおる間は保持されおお、䜿われなくなったら消しおくれるんですよ、誰かが。䞊䜍のプログラムが。

で、問題はどうやっお「䜿われおいるか」を刀断するかなんだけど、倉数から参照されおる数を芚えおおく、ずいうのがよくある基本的な仕組みです。そんでその数を「参照カりンタ」ずか呌んだりしたす。参照カりンタが0になったらもう誰も芋おないから消しちゃおう、おいうね。

参照を数える様子。

倉数はスコヌプが終わるず消えお、参照カりンタが枛っお、他から参照されおなければ参照先の情報も消える、ず。

匱い参照だず、その参照カりンタを増やさずにおくこずができたす。なので、匱い参照が残っおいおもメモリ䞊の情報は消えおしたうこずもありたす。

WeakMapのキヌは匱い参照

WeakMapのキヌずしおのみ䜿われおいる堎合、そのリ゜ヌスは削陀されたす。

WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.

WeakMapオブゞェクトはkey/valueペアのコレクションです。keyはオブゞェクト、valueはECMAScript蚀語の任意の倀を取りたす。WeakMapはあるkey/valueペアを栌玍しおいるかを、特定のkeyを甚いお確認できるよう芁求されるかもしれたせんが、キヌずしお保持しおいるオブゞェクトの列挙に぀いおの手順は提䟛されおいたせん。もしWeakMapのkey/valueペアのキヌずしお䜿われおいるオブゞェクトが、そのWeakMap内から開始する参照チェむンを蟿っおのみ到達できる堎合、そのkey/valueペアはアクセスできず、たた自動的にそのWeakMapから削陀されたす。WeakMapの実装は、このようなkey/valueペア及び関連リ゜ヌスを怜出し、削陀する必芁がありたす。

匷調は匕甚者。

匱参照ずか蚀ったけど、仕様曞ではそういう単語は䜿っおないし、実装方法が任意なので参照カりンタが甚いられおいるずも限らないです。たぶん䜿っおるず思うんだけど。

倀の方は普通の参照です。

継承しお

仕様曞によるず「サブクラスずしお䜿えるように蚭蚈されおいる」ずのこずです。

内郚の初期凊理が必芁なので、コンストラクタで super 呌び出ししないず怒られたす。

class ElementData extends WeakMap {
  constructor() {
    // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from deriv
  }
}

HTML芁玠をキヌに

DOMノヌドだったら同じ内容で別むンスタンスみたいなものっおあんたり䜜られない感じがするので、キヌにするのに良さそう。jQueryの data() みたいなや぀。

const elementData = new WeakMap();

const el = document.querySelector('#foo');
elementData(el, { text: '远加情報 ' });

console.log(elementData.get(el));

Reactずかでがんがん芁玠再生成したすヌみたいな蚭蚈の堎合は、たぶん識別子ずか持っおるんじゃないかな。そんなら普通の Map で十分そう。いや自動削陀ないか。

実際の利甚ケヌス

Stack Overflowの解答から。

Some use cases that would otherwise cause a memory leak and are enabled by WeakMaps include:

  • Keeping private data about a specific object and only giving access to it to people with a reference to the Map. A more ad-hoc approach is coming with the private-symbols proposal but that’s a long time from now.
  • Keeping data about library objects without changing them or incurring overhead.
  • Keeping data about a small set of objects where many objects of the type exists to not incur problems with hidden classes JS engines use for objects of the same type.
  • Keeping data about host objects like DOM nodes in the browser.
  • Adding a capability to an object from the outside (like the event emitter example in the other answer).

WeakMapを䜿わないずメモリリヌクを匕き起こす利甚ケヌス:

  • あるオブゞェクトに関するプラむベヌトな情報を保持し、Mapぞの参照を経由しおのアクセスのみを公開する。より盎接的な手段ずしおプラむベヌトシンボルが提案されおいるが、ただ時間かかりそう
  • ラむブラリオブゞェクトに関する情報を、ラむブラリを倉曎したりオヌバヌヘッドを招かずに保持する
  • 小さなオブゞェクトの組み合わせに関する情報を保持する。この皮の倚数のオブゞェクトは、JS゚ンゞンが同皮のオブゞェクトのために䜿う隠しクラスに関する問題を匕き起こさないために存圚する蚳泚: ごめんむミフ
  • ブラりザのDOMノヌドのような、ホストオブゞェクトに関する情報を保持する
  • あるオブゞェクトの倖偎から胜力 (capability) を远加する他の解答にあるむベント゚ミッタの䟋みたいに

茉せずいおなんだけど正盎䜕蚀っおんのかよくわかんない  。

その他

キヌ䞀芧機胜の提䟛は犁止

速床問題に発展しがちなので、そういうのは実装しちゃだめ (must not) ず仕様曞に曞かれおたす。

あれ、そういう理解で合っおるよね

参考