Symbolオブジェクト
新しく追加されたSymbolというオブジェクトです。
用途
通常の開発ではあまり使う機会はないかもしれません。JavaScriptは歴史のある言語なので膨大なライブラリがあり変数が競合してしまう可能性があるのでシンボルを使って競合を減らすという目的で使われていたりします。
基本
1 |
const symbol = Symbol(); |
シンボルは一度作った場合は必ず別オブジェクトになり一致はしません。
1 2 3 |
const symbol = Symbol(); const symbol2 = Symbol(); console.log(symbol === symbol2); //false |
オブジェクトのプロパティにもできる。
シンボルはオブジェクトのプロパティにもできますが、通常のプロパティと異なりドット(.)を使ってアクセスするわけではないです。
1 2 3 4 5 6 7 |
let obj = { name: "太郎", age: 25, [symbol]: 2 } console.log(obj.name); //太郎 console.log(obj[symbol]); //2 |
オブジェクトの中のシンボルを取得する。
オブジェクト内のシンボルにアクセスするには「getOwnPropertySymbols」というメソッドを使用します。
1 2 |
console.log(Object.getOwnPropertyNames(obj)); //これではアクセスできない。 console.log(Object.getOwnPropertySymbols(obj)); //アクセスできる。 |
戻り値は配列なので、下記のようにすればシンボルそのものにアクセスが可能です。
1 |
console.log(Object.getOwnPropertySymbols(obj)[0]); |
イテレーターとは?
順番に処理できるデータのことです。
構文
Symbolに対してiteratorという関数を実行する事でイテレーターを取得する事ができます。
1 2 3 |
let a = "a"; let iterator = a[Symbol.iterator](); iterator; |
イテレーターとして定義できるデータ型
デフォルトでイテレーターとして定義できるデータ型は決まっています。
- string
- 配列
next関数
next関数を使うとイテレータから一つずつ値を取り出す事が可能です。一度取り出した場所は記録されるので取り出す度に値が変わることになります。
1 2 3 4 5 6 7 8 9 10 |
let a = "abc"; let iterator = a[Symbol.iterator](); let b = iterator.next(); b; //{ value: 'a', done: false} let c = iterator.next(); c; //{ value: 'b', done: false} let d = iterator.next(); d; //{ value: 'c', done: false} let e = iterator.next(); e; //{ value: undefined, done: true} |
value
イテレータで取り出せた値です。もう値を取り出せない場合はundefinedが返ります。
done
取り出しが完了していない場合はfalse、取り出しが完了した場合はtrueが返ります。
イテレーターの自作
データ型がstringや配列の場合は自動でイテレーターとして値を取り出す事が可能ですが、自分でイテレータを自作することも可能です。next関数を用意してその中でvalueとdoneを返すような関数を作れば自作する事が可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
let a = { [Symbol.iterator]() { let data = [1, 2, 3] let num = 0; return { next() { return { value: data[num], done: num++ > 2 } } } } } let iterator = a[Symbol.iterator](); let b = iterator.next(); b; //{ value: 1,done: false } let c = iterator.next(); c; //{ value: 2,done: false } let d = iterator.next(); d; //{ value: 3,done: false } let e = iterator.next(); e; //{ value: undefined,done: true } |
ジェネレータとは?
ECMAScript2015から追加された関数に似た機能です。
用途
戻り値としてiterator(値を保持してくれる)を返すので、呼び出す度に値を更新してその値を保持する処理を作る際に使います。
基本構文
下記のように記述します。
1 2 3 4 5 6 7 8 9 |
function* gene() { yield 1; yield 2; } let a = gene(); a; console.log(a.next()); // { value:1, done: false } console.log(a.next()); // { value:2, done: false } console.log(a.next()); // { value:undefined, done: true } |
ポイント
- functionの末尾に*(アスタリスク)を付ける。
- function内にyieldキーワードを使う。
- 戻り値としてIteratorを返す。valueはyieldとして定義した値が返る。
イテレータのnextメソッドを実行した際の挙動
イテレーターのnextメソッドを実行した際はyieldが配置してある箇所まで実行されます。なので下記の例で言えば「あ」のみがコンソール出力されることになります。つまりyieldは通常の関数でいうところのreturnと似た挙動になります。
1 2 3 4 5 6 7 8 9 |
function* gene() { console.log('あ'); yield 1; console.log('い'); yield 2; } let a = gene(); a; console.log(a.next()); //「あ」と「{value:1,done:false}」が出力される。 |
オブジェクト内でジェネレータを定義するには?
オブジェクト内でジェネレータを定義する場合はfunctionキーワードを排除して定義します。
1 2 3 4 5 6 7 8 |
let person = { name: "太郎", age: 25, * gene() { yield 1; } } console.log(person.gene().next()); //{ value:1, done: false } |
リファクタリング
yield*の後に配列を定義することで複数行にyieldキーワードを並べる記述と同等の記述をする事ができます。yieldの間に処理は挟めませんが、単純にyieldを並べるだけの処理であれば下記のように記述する方が美しいコードと言えるでしょう。
1 2 3 4 5 6 |
function* gene() { yield* [1, 2]; } let a = gene(); console.log(a.next()); // {value:1,done:false} console.log(a.next()); // {value:2,done:false} |
この記事へのコメントはありません。