最近はjavascriptの処理系としてnode.jsではなくてSpiderMonkeyを使うように してる.それはたぶん、起動のコマンドが "node" よりも "js" のが短いから. (エイリアスかければいいだけだけど) それに、入出力関係や終了コマンドが短くラクだから. SpiderMonkeyの入出力は、readline() print()
入と出で一つずつしかないが、node.jsよりはずっとマシだ. 終了はquit()
と短いのもいい. でも最適化に関して、SpiderMonkeyよりもnode.jsの方が優れていることを 私は発見した.つまり、末尾再帰についてnode.jsでは答えを出すのに SpiderMonkeyではエラーが出る 確か私が試したのでは、普通に階乗を再帰で求めるというやつを実行してみてfunction fact(n) { if (n < 2) return 1; else return n * fact(n-1); }
これは割りとどちらでもすぐにスタックオーバーフローとか too much recursion とかエラーを吐いて答えを出せなかったfunction fact(n) { function fact_tail(n, acc) { if (n < 2) return acc; else return fact_tail(n-1, n*acc); } return fact_tail(n, 1); }
でやってみるとは有効数字表示やInfinity だとかいう答えを一応許せば n = 3000 のあたりでSpiderMonkeyは"too much recursion"を残して死ぬ 一方 node.jsはその10倍の n=30000 ほどでスタックオーバーフローとして 死ぬ. ただ末尾再帰を末尾再帰と分かる処理系なら、そもそもスタックを消費する はずはないので、これは醜い揚げ足取りだ. 本題. ブロックが変数にスコープを与えないということ. C/C++ に代表される手続き型言語では { } に囲まれるステートメント をブロックとよび、ブロックの初めでは変数を宣言するのがC言語の スタイルである.C99とか(もしかしたら違うかも、とにかくC言語の 新しい規格)C++では途中でも変数の宣言をできるけど. その変数が使えるのは、宣言文のあるブロックの中で、宣言文以下 である.即ちそれがスコープであろう. 関数の宣言はブロックであり、forループ、whileループもブロックである. javascriptにおいて、変数にスコープを与える、つまり変数の参照に 制限を与えるブロックは関数宣言だけである.js> i typein:8: ReferenceError: js is not defined js> for (var i=1;i<10;++i); js> i 10 js> for (var i=10;i<20;++i); js> i 20
あー、でもfor(){}の()の中はブロックって言えるのかな. たぶん言うよね.js> k typein:15: ReferenceError: k is not defined js> for (i=0;i<10;++i) { var k = 1} js> k 1 js> for (i=0;i<10;++i) { k = 3; } 3 js> k 3
var の有り無しによる挙動の変化はたまに罠になる. 上のコードでは変化は無いけれど.forループ、whileループのブロックの中での変数は その一つ外の変数と同じである.
こんなことはjavascriptを知っていると言う人なら みな知っており、従って次のような技巧的な書き方も 知られている.js> var s = 0; js> (function(){ var s = 1; print(s); })(); 1 js> s 0
functionブロックは変数にスコープを与える. 即ち、ブロックの中でvarをつけた変数宣言は関数の中でのみ 参照できるものであり、同じ名前の変数が外にあってもそちらは 参照されない. スコープを利用して安全なコードを書きたいがために 上のように無名関数を宣言し、それを即座に実行する書き方は 見た目はよろしくないが、確かに見ることはある. 関数の宣言と実行を同時にする書き方としてfunction(){return 1}()
と書いて動くのもあるが、動かないのもある. 動かないものとは即ちSpiderMonkeyであり、以下のように書けば 普通どの処理系でも動く(function(){return 1})()
関数の宣言をカッコでくくるのである. var を付けない変数宣言というのは単なるグローバル変数への 代入文であり、js> var s = 0; js> (function(){ s = 1; print(s); })(); 1 js> s 1
となるので註意.
コメ(0) | トラ(0)