Function Expression Statements ― 2005年12月10日 21時32分
もじら組フォーラムで書いたことを再掲。以下 JavaScript といった場合 JScript などは含まないものとする。
JavaScript の function
ECMAScript 3 で function
キーワードが使われる構文には FunctionDeclaration
と FunctionExpression
があり、以下のように定義されている。
FunctionDeclaration
function
Identifier
(
FormalParameterList
opt
)
{
FunctionBody
}
FunctionExpression
function
Identifier
opt
(
FormalParameterList
opt
)
{
FunctionBody
}
FunctionBody
SourceElements
Program
SourceElements
SourceElements
SourceElement
SourceElements
SourceElement
SourceElement
Statement
FunctionDeclaration
これをみればわかるとおり、FunctionDeclaration
はプログラム直下か関数本体の直下にしか置けない。下の例でいうと (1) は問題ないが (2) は ECMAScript としては正しくないということだ。(2) の場合 g
は FunctionExpression
とみなされるのではと思うかもしれないが、ExpressionStatement
を function
キーワードで開始することはできないのでそれも成り立たない。
// (1)
function f() {
function g() {}
}
// (2)
function f() {
do {
function g() {}
} while (false);
}
しかし、JavaScript ではバージョン 1.5 から Function Expression Statements という機能が追加され、通常の文が置ける場所ならどこでも関数を定義できるようになった (すなわち JavaScript では (2) も正しいコードである) 。ここではこれを仮に FunctionStatement
と呼ぶことにする。
FunctionStatement
function
Identifier
opt
(
FormalParameterList
opt
)
{
FunctionBody
}
FunctionDeclaration
と FunctionStatement
の最大の違いは処理されるタイミングである。FunctionDeclaration
はコンパイル時に処理されるその宣言が含まれる関数 (宣言がトップレベルにある場合はプログラム全体) の実行に先立って処理されるが FunctionStatement
は実行時に処理される。また、FunctionExpression
との違いとして、FunctionExpression
の Identifier
は FunctionBody
内でのみ有効だが、FunctionStatement
では文の評価後にその Identifier
を使って関数を参照できるようになることが挙げられる。
以上の特徴から、if 文を使った関数定義の振り分けなどもできる。
// (3)
var condition = true;
if (condition) {
function f() {
return true;
}
} else {
function f() {
return false;
}
}
alert(f()); // JavaScript (Firefox など) では true
また、FunctionStatement
が実行時に処理されるということは、その文の評価前はその関数を参照できないということでもある。以下のコードは JavaScript では例外が投げられる。
// (4)
try {
f();
function f() {
alert("Succeed!");
}
} catch (e) {
alert(e); // ReferenceError: f is not defined
}
なお、FunctionStatement
に Identifier
が存在する場合、FunctionStatement
の文としての返り値は空値 (empty) になるが、Identifier
が存在しない場合はその関数オブジェクトが返る。ただし Firefox 1.0 では Identifier
を省略できない (省略するとシンタックスエラーになる) 。
JScript の function
だが、Function Expression Statements はあくまでも JavaScript だけの機能であり、JScript などでは実装されていない。しかし、JScript や Opera の ECMAScript 実装でも任意の場所に function 文を置くことができる。ただし、それが処理されるのはコンパイル時であり、JavaScript のような動的な関数定義はできない。それが証拠に IE や Opera で上記 (3) のコードを実行してみると false と表示される。
さらに、JScript の場合は、FunctionExpression
さえもコンパイル時に処理し、その Identifier
を変数オブジェクトに登録してしまう。結果以下のコードで "Hello" と表示されてしまうのである。これは明らかに ECMAScript に違反している。
// (5)
alert(f()); // "Hello"
var g = function f() { return "Hello"; };
alert(f == g); // false
最近のコメント