ある関数内で外のスコープの変数を使用する場合。
var message = "test";
var func = function(){
alert(message);
};
func(); // test
message = "change";
func(); // change
funcを定義した後に変数の値を変更するとfuncの実行結果も変わる。
また、関数が定義されたスコープの外でその関数を実行する場合。
var func;
(function(){
var message = "test";
func = function(){
alert(message);
}
})();
alert(message); // undefined or not defined
func(); // test
message = "change";
func(); // test
変数message
のスコープは7行目で終わっているはずだが
定義したfuncを使うことで値を取得できる。
ということは上のケースもこちらのケースも
関数内で使用した変数がどのスコープからでも参照できているということか。
調べてみるとこの概念をクロージャというらしい。
なるほど。JavaScriptにおけるクラス定義は
このクロージャという概念を使って定義されているわけだ。
ちなみに最初のケースで定義時の変数の値を使用したい場合はevalを使って定義するとできる。
var message = "test";
var func = eval("(function(){" +
"return function(){" +
"alert(\"" + message + "\");" +
"}" +
"})()");
func(); // test
message = "change";
func(); // test
文字列で書くとデバッグできなさそうだが、最近のブラウザなら
うまいことやってくれるのであんしん。
クラスでメンバーを定義するときのやりかたを思い出すと
クロージャの概念をうまく使ってevalを使わずにできそうだ。
var message = "test";
var func = (function(){
this.msg = message;
return function(){
alert(this.msg);
};
})();
func(); // test
message = "change";
func(); // test
デバッグは問題なくできるとはいえ、evalを使う方法だと可読性が落ちるので
こっちのほうがいいかな。
あ、でもfuncにcallやapplyでthisを渡したいときはダメだな。
thisを使わなくても普通に変数定義したらできた。
var message = "test";
var func = (function(){
var msg = message;
return function(){
alert(msg);
};
})();
func(); // test
message = "change";
func(); // test
あれ?クラスのメンバ変数ってthis省略できないんじゃなかったっけ?
クラス定義してるわけじゃないからいいのか?まあいいか。
あ、引数渡しでもいけるな。
var message = "test";
var func = (function(msg){
return function(){
alert(msg);
};
})(message);
func(); // test
message = "change";
func(); // test
この辺のスコープの自由さがJavaScriptの自由さって感じがするね。