比較言語学
JavaScript ご存知の方には面白くない話だと思うので無視してください。ただの備忘録です。
JavaScript では、以下の 3つが区別されます。
- 変数に null が代入されている状態
- 変数が「undefined である」状態
- 変数が「宣言されていない」状態
面白い言語ですね。明示的に宣言していない変数に値を代入すると、その時点でグローバル変数として宣言されたことになるくせに、しかし宣言されていない変数を評価するとエラーになります。つまり宣言していない変数は、undefined ではない訳ですね。変数に型のない言語で有名(?)なものに AWK がありますが、AWK では宣言していない変数*1を評価すると、あたかも null のように扱われます。数値コンテキストで評価すると 0 になりますし、文字列コンテキストで評価すると "" になります。この点で、AWK と JavaScript は異なります。
また、変数がブロックスコープを持たない点と、関数中のいずれかの箇所で宣言したローカル変数が、宣言箇所よりも前でも有効というのも面白い特徴です。つまり、
var a = 3; function foo() { document.write(a); var a = 5; document.write(a); } foo();
とすると、最初の document.write() では "undefined" が表示され、後者では 5 が表示されます。
でも、よくよく考えてみると、これって Python と同じかも。Python では、次のコードを実行すると foo() の評価でエラーになります。(最初の print で、UnboundLocalError: local variable 'a' referenced before assignment になります。)
a = 5 def foo(): print a a= 7 print a foo()
ちなみに Python では、global キーワードで強制的にグローバル変数をアクセスできるけど、JavaScript で同じことをするには、関数内で var キーワードで宣言しなければ良いのか。なるほど。つまり Python ならば
a = 5 def foo(): global a print a a= 7 print a foo() print a
JavaScript ならば、
var a = 5; function foo() { document.write(a); a = 7; document.write(a); } foo(); document.write(a);
ですね。
参考: Python のスコープについて
重箱の隅
JavaScript 1.2 時代(?)には、クラスの継承には prototype.__proto__ を使えとありますが、ECMA 標準では盛り込まれていないようです。どうしたらいいんだ? あ、古いバージョンの JavaScript では読み出し専用だった constructorが単に書き換え可能になっただけかー。つまり、こういうことね。
// This is a superclass. function Human(name, sex) { this.name = name; this.sex = sex; } Human.prototype.getName = function() { return this.name; } // This is a subclass of the superclass. function Employee(name, sex, title) { this.name = name; this.sex = sex; this.title = title; } Employee.prototype = new Human(); Employee.prototype.constructor = Employee; // This recovers its constructor // property. Employee.prototype.getTitle = function() { return this.title; } john = new Human("John", "male"); document.write("His name is " + john.getName() + ".<br>"); kate = new Employee("Kate", "female", "director"); document.write("Her name is " + kate.getName() + ".<br>"); document.write("Her job title is " + kate.getTitle() + ".<br>"); // document.write("His job title is " + john.getTitle() + ".<br>"); // Error document.write("Constructor is '" + kate.constructor.toSource() + "'.<br>");
この辺にも書いてありました。
参考: http://www.quantumwave.com/flash/inheritance.html
配列
JavaScript では、多次元配列はサポートされないそうな。明示的に、配列オブジェクトの配列としてやらなければならないらしい。まだ、ちゃんと本読んでないんだけど、こんな感じかな、と、でっち上げてみました。
var a = new Array(); for (var i = 1; i <= 9; i ++) { a[i] = new Array(); for (var j = 1; j <= 9; j ++) { a[i][j] = i * j; } } document.write("<table border=\"1\">"); for (var i = 1; i <= 9; i ++) { document.write("<tr align=\"right\""); for (var j = 1; j <= 9; j ++) { document.write("<td>" + a[i][j] + "</td>"); } document.write("</tr>\n"); } document.write("</table>");
すいません。間違ってたら許して。HTML も少し怪しいけど許して。