Symbolについて
ES2015(ES6)で追加されたgenerators(yield)
generatorsを使うにはSymbol、Iteratorを理解しておいた方がいいので順番に説明していきます
今回は「Symbol」についてです
概要
ES2015で追加された新しいプリミティブです
数値でも文字列でも真偽値でもない値ですが
文字列のようにオブジェクトのプロパティのキーとして使えます
またObject.keys、Object.getOwnPropertyNamesでも列挙できないという特徴を持っています
作り方
var s = Symbol(); var s = Symbol('foo'); // 引数に文字列を渡すことでSymbolの説明を追加することができる
念のためtypeof演算子で確認するとSymbolであることがわかります
typeof s; // "symbol"
またnew演算子付きで呼ぶとType Errorとなるので注意
var s = new Symbol(); // Type Error
使い方
Symbolはオブジェクトのプロパティのキーにすることができます
var obj = {}; var s = Symbol(); obj[s] = 'hoge'; console.log(obj[s]); // hoge
ちなみに、ES2015のComputed Property Namesを使えば下記のように書けます
var s = Symbol(); var obj = { [s]: 'hoge' }; console.log(obj[s]); // hoge
シンボルは暗黙的に文字列変換されるわけではないので、下記の場合undefinedになります
console.log(obj[s.toString()]); // undefined
特徴
Symbolは毎回異なるシンボルが作成されます
Symbol('foo') === Symbol('foo'); // false
この特徴を活かして、ES2015は既存のコードに影響がでないように
機能を追加できるようにしたようです
例えば、
function test(obj, value) { obj._value = value; }
上記のようなコードの場合、外部から勝手にobjのプロパティを上書きされて全く別のものになったり
キーがシンボルではないので普通に外部から参照できてしまいます
↓このようにすることで、外部からいじられる心配も、参照される心配もありません
var obj = {}; var _value = Symbol(); function test(obj, value) { obj[_value] = value; } test(obj, 123);
キーがシンボルなので同じキーを外部から作れないためです
ただし、Object.getOwnPropertySymbolsでシンボルを取得できてしまうので
完全に隠蔽できるわけではないです
console.log(obj[Object.getOwnPropertySymbols(obj)[0]]); // 123
登録
シンボルは毎回異なるシンボルが作成されますが
Symbol.forを使ってシンボルを登録すると共有することが可能です
引数で与えられたキーでランタイム全体のシンボルレジストリ内に存在しているシンボルを検索し、見つかった場合それを返します。さもなければ、新しいシンボルがこのキーでグローバルシンボルレジストリ内に生成されます。
↓こんな感じでシンボルを共有できます
var s1 = Symbol.for('foo'); // ここでは新しく作成される var s2 = Symbol.for('foo'); // 作成されているシンボルを参照 var s3 = Symbol('foo'); // これはグローバルシンボルレジストリに生成されてないシンボルの作成 s1 === s2; // true s1 === s3; // false
Well-Known Symbols
ウェルノウンシンボルという特別なシンボルがあります
「特別なシンボル」と書くと、何かすごい機能があるように思えますが、ごく普通のシンボルです
JavaScriptの内部処理で参照されるシンボルです
このウェルノウンシンボルの中にSymbol.iteratorというシンボルがあります
IteratorはこのSymbol.iteratorを使うことで実現します