Re:Start jQuery #005

オブジェクトのキーに変数を使う

今回もjQueryといよりJavaScriptの話。

こんなオブジェクトがあったとする。

さて、umlgofを指定して値を取り出してみる。

これはもちろんThree Amigosと表示される。
当然、

でも同じだ。

モダン環境だと、後者のブラケットは使わず、前者のドットでつなげてくれと警告が出る。

そして次は、このumlを変数にいれてアクセスしてみる。

残念ながらこれはundefinedになる。なぜか?

dataの中にkeyという名前のキーが無いから。あるのはumlgofの2つだけ。
つまりドットアクセスだとリテラルとして解釈されてしまう。

ではどうするのか。

ブラケットを使う。

これなら正しくThree Amigosが表示される。

json形式にしてみる

まずは普通にオブジェクトを作っていじってみる。

これはObject {k1: "v1", k2: "v2", k3: "v3"}と表示される。

このdataオブジェクトにkey3を追加し、中身をval3にしてみる。

tmp00163

正しく追加された。

今度はkey3の中身をオブジェクトにしてみる。

tmp00164

こちらも特に問題なく代入できてる。

さて準備は万端だ。このオブジェクトを文字列にしてしまおう。
つまりJSON文字列だ。

tmp00165

正しく文字列になった。

これはどういうときに使うのかと言うと、たとえばローカルストレージに保存する際、データはJSON形式そのままでは入れられず、文字列しか入れられないので、この方法を使ってオブジェクトを文字列にするわけだ。

反対に文字列からオブジェクトを生成するには、JSON.parse()を使えばいい。

Object.defineProperty()

オブジェクトにキーと値を追加するメソッドがある。
Object.defineProperty()

これは、オブジェクトに新たにプロパティを追加、もしくは変更するメソッドだ。
これを使ってオブジェクトにキーを変数として追加してみよう。

tmp00166

正しく追加できた。

しかしよく見ると、key3の色が薄い。これはなんだろうか。

実はObject.defineProperty()にはディスクリプタを指定でき、それぞれこういう意味になる。

  • writable
    • 値の変更可能かどうか
  • enumerable
    • 列挙可能(forEachなどで拾えるか)どうか
  • configurable
    • ディスクリプタ自体の変更を許可するかどうか

__proto__はforEachでまわしても表示されない。これは列挙不可になってるからだ。

このkey3も実は列挙不可になってしまっている。これではデータをイテレートして中身を拾うことができない。

ではどうするか。ディスクリプタで個別に指定すればよい。

tmp00167

これで列挙可能になった。
なかなか興味深い仕組みである。

JSONにするときの注意

実はブラケットで代入、ドットで代入するのと違い、Object.defineProperty()で代入する際には注意が必要になる。
JSON.stringify()したときに空になるのだ。

tmp00168

これは前述した列挙がfalseになってるのが原因。

こうすればOK。

tmp00169

まとめ

Object.defineProperty()の使いどころは難しいかも。

ちなみにアクセサもディスクリプタに書けるので、それなりにおもろい使い方(メタっぽい感じとか)できそう。