var@JS vs let@O'Caml, Lisp


JavaScript の var はいろいろ癖があるようですが、また遭遇してしまいました。var のスコープには var 宣言される変数自身までもが含まれているような気がします。

var a = 0;
(function () {
var a = a;
print(a);
})();

たとえば、この例で問題となるのは3行目です。わたしが期待した動作は3行目のaに1行目で宣言されたaの値(つまり0)が指定され、その結果 0 が出力されるというものです。残念ながら、このプログラムを実行すると undefined が表示されます。

同じことを Objective Caml でも試してみました。期待どおり 0 が表示されます。

let a = 0 in
let a = a in
print_int a

Scheme でも同様です。

(define a 0)
(let ((a a))
(display a))

ECMAScript の仕様書を読んでもそのあたりのところがよく分りません。最新の ECMAScript の仕様書は何が書いてあるのかさっぱり分らない。

var@JS vs let@O'Caml, Lisp」への4件のフィードバック

  1. お久しぶりです。kei_sです。
    面白そうなJSのお話なのでコメントさせていただきます。

    ECMAScriptの仕様によると変数はスコープに入ったときに生成されるようです。
    「変数は実行スコープに入ったときに生成される。」
    http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/12_Statements.html#VariableStatement

    なので、上のコードは内部的には以下のようにシミュレートされると思います。
    var a = 0;
    (function () {
    var a;
    a = a;
    print(a);
    })();
    これだとaはundefinedで正しい挙動だと思います。

    http://openlab.dino.co.jp/2007/09/20/20021368.html
    この辺りを参考にして調べてみました。

  2. kei_s さん、ごぶさたしています。また、遊びに来てください。

    コメントをありがとうございます。やっぱりそうなんですね。普通の関数型言語だとこれが、

    var a = 0;
    (function () {
    var _ = a;
    var a = _;
    a = a;
    print(a);
    })();

    となって 0 になるので、ちょっとした違いとなりますね。小さな違いというのは怖いですね。注意しないと。。。

  3. ちなみに、Javascript 1.7 から導入されたlet文を使うとできますね。
    var a = 1;
    let (a=a*2) {
    print(a);
    }
    print(a);
    // => 2
    // => 1
    let宣言にするとvar宣言と同じく実行前に処理されてしまいダメですが・・・
    var a = 1;
    {
    let a=a*2;
    print(a);
    }
    print(a);
    // => NaN
    // => 1

    # またご一緒させてください!

  4. JavaScript 1.7 の使い方が分ってませんでした。Firefox だけでなくて、Safari でも利用できたんですね。どうもありがとうございます。

コメントは受け付けていません。