2014-04-23

JavaScriptのオブジェクト初期化子

JavaScriptでは、オブジェクトをリテラル風に式の中に書くことができる。これは、オブジェクト初期化子(Object Initialiser)とか、オブジェクトリテラル(Object Literal)と呼ばれている。その文法は、{ }の中にプロパティを記述する。

var a = {} ;
var b = { PropertyName : AssignmentExpression } ;
var c = { A : 1, B : 2, C : 3 } ;

プロパティ名とその値のペアを、コロンで区切って指定する。そしてカンマで区切る。

オブジェクト初期化子は、{}内の最後をカンマで終わらせることもできる。

{ A : 1, } ;

これは、やや気持ち悪い文法だ。

PropertyNameには、識別子と文字列リテラルと数値リテラルを書くことができる。

var x = {
// 識別子
IdentiferName : 0,
// 文字列リテラル
"StringLiteral" : 0,
// 数値リテラル
3.14 : 0 
} ;

さて、オブジェクト初期化子のプロトタイプに文法には、もうひとつ、getter/setter、あるいは、アクセッサーなどと呼ばれているものを記述する文法がある。文法は関数式に似ているが、functionキーワードのかわりに、get/setを用いる。

function X( val )
{
    this.value = val ;
}

X.prototype = {
    get value() { return this._value ; }
    set value( val ) { this._value = val ; }
} ;

var x = new X(0) ;
x.value ; // 0
x.value = 10 ;
x.value ; // 10
x.value += 10 ;
x.value ; // 20 

アクセッサーは、通常の関数呼び出しの文法を使わずに、同じ識別子で、値の設定と取得を、単なる参照と代入というわかりやすい文法で行うことができる機能である。これは、例えば以下のように書くより、格段にコードがわかりやすくなる。


function X( val )
{
    this.value = val ;
}

X.prototype = {
    function get_value() { return this.value ; }
    function set_value( val ) { this.value = val ; }
} ;

var x = new X(0) ;
x.get_value() ;
x.set_value(10) ;
x.get_value() ;
x.set_value( x.get_value + 10 ) ;
x.get_value() ;

ちなみに、Where's Walden? » More SpiderMonkey changes: ancient, esoteric, very rarely used syntax for creating getters and setters is being removedによれば、アクセッサーの文法には、実に様々な歴史的な非標準の方言があったようだ。特にMozillaのものだが。

まず、__defineGetter__/__define_Setter__がある。これは、Object.definePropertyを使うべきである。

かつて、SpiderMonkeyのJavaScriptのパーサーに問題があったため、以下のようなコードが通ってしまっていた。

var x = { get a b() { return "get" ; } } ;

また、アクセッサーの生みの親であるNetscapeの当初の文法は、以下のものであったらしい。

function g() { print("gotten!"); return "get"; }
var o1 =
  {
    property getter: g,
    property setter: function(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!"

SpiderMonkeyはこれをしばらくサポートしていた。

また、アクセッサープロパティを付け加えるSpiderMonkey独自の文法として、以下のようなものもあったらしい。

var o = {};
o.property getter = function() { print("gotten!"); return "get" };
o.property setter = function() { print("sotten!"); };
var v = o.property; // prints "gotten!", v === "get"
o.property = "new"; // prints "sotten!"

うーん・・・。

SpiderMonkeyの独自文法はまだある。

getter function foo() { return "foo getter"; };
var v = foo; // "foo getter"
var q = setter function bar(v) { };

うーむ。

そういえば、strict modeのとき、PropertyAssignmentの中のPropertySetparameterListの識別子として、"eval"と"arguments'が現れると文法エラーというのは、どういうことだろう。コード例で言えば、以下のようなものだが。

"use strict" ;

// SyntaxError
var x = { set setter( eval ) { } } ;

なぜ、数あるキーワードの中でevalとargumentsだけが特別に禁止されているのか。ちょっと調べただけでは出てこない。もうすこし規格を読み進める必要がありそうだ。

ドワンゴ広告

この記事はドワンゴ勤務中に、十分な昼寝とカタンをした後に、書かれた。睡眠は重要である。カタンも重要である。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

1 comment:

Anonymous said...

with文と同様に、evalとargumentsが最適化に影響を与えるからです。