情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

ECMAScript 6の新機能(10)配列やオブジェクトの分解

オブジェクトの分解

ECMAScript 5で使用できたオブジェクトの構築とは下のような操作でした。

C:\work\node>node
> var obj = { foon: 100, barn: 200 }
undefined
> obj.foon
100
> obj.barn
200

そして、ECMASCripr 6で追加されたオブジェクトの分解とはオブジェクトの構築とは逆の、下のような操作です。

> var { foon: f, barn: b } = obj
undefined
> f
100
> b
200

すなわち、オブジェクトを構築するのと似た記法で逆にオブジェクトのプロパティの値を変数に格納することができます。ただし、プロパティ名と:の後に指定するのは値ではなく変数名です。

一部のプロパティの値のみを変数に格納したい場合にはそのプロパティや関数のみを指定します。

> var { barn: b2 } = obj
undefined
> b2
200

また、プロパティ名と変数名を同名にしたい場合には:と変数名を省略することができます。

> var { foon, barn } = obj
undefined
> foon
100
> barn
200

なお、分解するものとして数値や文字列などを指定した場合にはオブジェクトとしての数値や文字列などのプロパティの値を取り出すことができます。

> var { length: l } = 'foon'
undefined
> l
4
> var { toString: tos } = 100
undefined
> tos
[Function: toString]
> tos.call(200)
'200'

ただし、undefinednullを指定するとエラーとなりますので注意してください。

C:\work\node>node
> var { foon } = undefined
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:16
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:224:10)
    at REPLServer.Interface._line (readline.js:566:8)
    at REPLServer.Interface._ttyWrite (readline.js:843:14)
> var { foon } = null
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:224:10)
    at REPLServer.Interface._line (readline.js:566:8)
    at REPLServer.Interface._ttyWrite (readline.js:843:14)

配列の分解

ECMAScript 5で使用できた配列の構築とは下のような操作でした。

C:\work\node>node
> var array = [0, 1, 2]
undefined
> array[0]
0
> array[1]
1
> array[2]
2

そして、ECMASCripr 6で追加された配列の分解とは配列の構築とは逆の、下のような操作です。

> var [x, y, z] = array
undefined
> x
0
> y
1
> z
2

すなわち、配列を構築するのと似た記法で逆に配列の要素の値を変数に格納することができます。ただし、[]の間に指定するのは値ではなく変数名です。

配列の要素の数より少ない数の変数名を指定した場合には変数には配列の先頭の要素から順番に値が格納されます。

> var [x2, y2] = array
undefined
> x2
0
> y2
1

一部の要素を変数に格納したくない場合には変数名を指定しないでおきます。

C:\work\node>node
> var [, , z] = [100, 200, 300]
undefined
> z
300

また、現在の要素から最後の要素までの全ての要素を1つの変数に配列として格納したい場合には変数名の前に...を付加します。

C:\work\node>node
> var [, , z] = [100, 200, 300]
undefined
> z
300
> var [x, ...ys] = [100, 200, 300]
undefined
> x
100
> ys
[ 200, 300 ]

なお、分解するものとして配列以外のイテラブルを指定することもできます。

C:\work\node>node
> var [x, y] = 'foon'
undefined
> x
'f'
> y
'o'

分解するものとしてイテラブル以外のものを指定するとエラーとなります。

C:\work\node>node
> var [x1, y1] = 1
TypeError: undefined is not a function
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)
> var [x2, y2] = {}
TypeError: undefined is not a function
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)
> var [x3, y3] = undefined
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:18
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)
> var [x4, y4] = null
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)

分解が使用できる場所

分解は変数の宣言においてだけではなく下のような場合に使用することができます。

変数への代入

C:\work\node>node
> var x = 9
undefined
> var y = 9
undefined
> var z = 9
undefined
> [x, y, z] = [0, 1, 2]
[ 0, 1, 2 ]
> x
0
> y
1
> z
2
C:\work\node>node
> var fn = 0
undefined
> var bn = 0
undefined
> { foon: fn, barn: bn } = { foon: 100, barn: 200 }
{ foon: 100, barn: 200 }
> fn
100
> bn
200

関数の引数

C:\work\node>node
> function f ([x, y]) {
... console.log(x);
... console.log(y);
... }
undefined
> f([0, 1, 2])
0
1
undefined
C:\work\node>node
> function f ({ foon : fn }) {
... console.log(fn);
... }
undefined
> f({ foon: 100, barn: 200 })
100
undefined

for-of文

C:\work\node>node
> var array = [
... [100, 200, 300],
... [1001, 2002, 3003]
... ]
undefined
> for (var [x, y] of array) {
... console.log(x);
... console.log(y);
... }
100
200
1001
2002
undefined
C:\work\node>node
> var array = [
... { foon: 100, barn: 200 },
... { foon: 1001, barn: 2002 }
... ]
undefined
> for (var { foon: fn, barn: bn } of array) {
... console.log(fn);
... console.log(bn);
... }
100
200
1001
2002
undefined

入れ子

分解を入れ子にすることもできます。

C:\work\node>node
> var array = [
... { foom: 100, barm: 200 },
... {}
... ]
undefined
> var [{ foom: fm }] = array
undefined
> fm
100
> var obj = { m: { mmmm: 1000 } }
undefined
> var { m: { mmmm } } = obj
undefined
> mmmm
1000

上の場合mという変数は宣言されないことに注意してください。

> m
ReferenceError: m is not defined
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)

変数mと変数mmmmの両方が必要な場合には下のように2回に分けて宣言することになるでしょう。

C:\work\node>node
> var array = [
... { foom: 100, barm: 200 },
... {}
... ]
undefined
> var obj = { m: { mmmm: 1000 } }
undefined
> var { m } = obj
undefined
> var { mmmm } = m
undefined
> mmmm
1000
> m
{ mmmm: 1000 }

また、分解を入れ子にする場合にも...を使用することができます。

C:\work\node>node
> var [x, ...[y, ...zs]] = [100, 200, 300, 400]
undefined
> x
100
> y
200
> zs
[ 300, 400 ]

プロパティや要素などが存在しない場合

分解するものに変数に対応するプロパティや要素などが存在しない場合には変数の値はundefinedとなります。

C:\work\node>node
var [x, y] = []
undefined
> x
undefined
> y
undefined
> var { foon, barn } = {}
undefined
> foon
undefined
> barn
undefined

そのため、存在しないプロパティや要素などに対して入れ子の分解が行われた場合にはエラーとなりますので注意してください。

C:\work\node>node
> var [ [x1, x2], y1] = []
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)
> var { foon : { foon1, foon2 } , barn } = {}
TypeError: Cannot match against 'undefined' or 'null'.
    at repl:1:1
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)

ただし、...が付加されている変数に対応する要素が存在しない場合には変数の値は[]となります。

C:\work\node>node
> var [x, y, ...zs] = [100]
undefined
> x
100
> y
undefined
> zs
[]

また、分解において宣言する変数にはデフォルト値を指定することができます。

デフォルト値が指定された場合、変数に対応するプロパティや要素などが存在しない場合には変数の値はデフォルト値となります。

C:\work\node>node
> var { foon, barn = 999 } = { foon: 100 }
undefined
> foon
100
> barn
999
> var [x, y = 999] = [100]
undefined
> x
100
> y
999

また、変数に対応するプロパティや要素などの値がundefinedである場合にも変数の値はデフォルト値となります

C:\work\node>node
> var { foon, barn = 999 } = { foon: 100, barn: undefined }
undefined
> barn
999

デフォルト値を設定する際には既に定義されている変数の値を使用することもできます。

C:\work\node>node
> var bn = 999
undefined
> var { foon, barn = bn * bn } = { foon: 100 }
undefined
> barn
998001

それは分解において宣言した変数でも構いません。

C:\work\node>node
> var { foon = 999, barn = foon * foon } = {}
undefined
> foon
999
> barn
998001
C:\work\node>node
> var { foon = 999, barn = foon * foon } = { foon: 100 }
undefined
> foon
100
> barn
10000

ただし、分解において自分より後ろで宣言している変数の値を使用することはできません。

C:\work\node>node
> var { foon = barn * barn, barn = 999 } = {}
ReferenceError: barn is not defined
    at repl:1:16
    at REPLServer.defaultEval (repl.js:272:27)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:441:10)
    at emitOne (events.js:101:20)
    at REPLServer.emit (events.js:188:7)
    at REPLServer.Interface._onLine (readline.js:219:10)
    at REPLServer.Interface._line (readline.js:561:8)
    at REPLServer.Interface._ttyWrite (readline.js:838:14)

変数以外への格納

分解した値はオブジェクトのプロパティや配列の要素に格納することもできます。

C:\work\node>node
> var obj = {}
undefined
> var array = []
undefined
> [obj.foon, array[0]] = [100, 200]
[ 100, 200 ]
> obj.foon
100
> array[0]
200

デフォルト値を指定することもできます。

> [obj.foon = 999, array[0] = 999] = []
[]
> obj.foon
999
> array[0]
999
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-ecmascript 2015, ecmascript 6, Javascript