Note: この記事は、3年以上前に書かれています。Webの進化は速い!情報の正確性は自己責任で判断してください。
一度しっかり試しておきたかった変数とその有効範囲について。
- JavaScriptには変数の型という考え方がない(任意のデータ型の値を代入できる)
- JavaScriptでサポートされるデータ型には、基本型と参照型がある
- 参照型の変数には、参照が格納される(実際のデータ値ではない)
- 関数、配列、オブジェクトなどが参照型
- 変数の有効範囲を、その変数のスコープという
- 暗黙的に宣言された変数は、必ずグローバル変数になる
- 関数の内部で暗黙的に宣言された場合でも、グローバル変数になる
- var文で宣言した変数は、ローカル変数になる
- ローカル変数のスコープは、その変数が宣言された関数の中だけに限定される
- 関数の中にグローバル変数と同じ名前のローカル変数があった場合は、ローカル変数が優先される
- ある関数で宣言された変数は、「関数全体」で有効(値はともかく、宣言自体に順序は関係ない)
- 関数の引数もローカル変数の仲間
var a = 3.14;
var b = a;
a = 4;
alert(b); // 3.14 が出力される
var c = [0,1,2];
var d = c;
c[0] = 99;
alert(d); // [99,1,2] が出力される
前半が基本型。変数 a と b は違う値。後半が参照型の数値を使用するコード例。変数 c と d は同じ配列を参照している。
var scope = "global";
function f(){
alert(scope); // 「undefined」が表示される
var scope = "local"; // 初期値はここで設定される。宣言自体は関数全体で有効
alert(scope); // 「local」が表示される
}
f();
グローバル変数と同じ名前のローカル変数が宣言された場合、グローバル変数はローカル変数で隠される。そして変数の宣言自体は、どこに書いたとしても関数全体で有効(値の代入は記述順に従う)。一般的なJavaScriptソースにおいて、変数宣言が冒頭に集中する理由はここにある。
参照: David Flanagan 著, 村上 列 訳, 『JavaScript 第五版』
テスト
// 準備
var foo = 10;
var hoge = function(foo){
foo = foo + 100;
alert(foo);
};
// 実行
hoge(foo); // 110
alert(foo); // 10
関数 hoge() 内で弄った変数の値は、hoge() 内でのみ有効。
// 準備
var foox = 50;
var fooa = 10;
var hoge = function(foo){
var foob = foo + 100;
alert(foox); // 50
alert(foob); // 110
};
// 実行
hoge(fooa);
alert(fooa); // 10
alert(foob); // "foob is not defined"
内側から外側にはアクセスできる。
外側から内側にはアクセスできない。
ちなみに、以下のように書くこともできる。
// 準備
var foo = 10;
(function(foo){
foo = foo + 100;
alert(foo);
}).call(this, foo);
// 実行
alert(foo);
なんかプロっぽい。
この場合、匿名関数の内側でスコープが一段下がっているため、匿名関数内で定義した変数はグローバルな名前空間を汚染しない。なので、その場限りで使い捨てることができる。便利。
オブジェクトの場合
// 準備
var foo = new Object();
foo.x = 50;
foo.a = 10;
var fxx = new Object();
fxx.x = 50;
fxx.a = 10;
var hoge = new Object();
hoge.hoge1 = function(){
this.z = foo.a + fxx.a;
alert(this.z);
}
hoge.hoge2 = function(){
foo.a = foo.a + 200;
alert(foo.a);
}
hoge.hoge3 = function() {
var num = foo.a + 300;
var abc = 'variable';
return num;
}
// 実行
hoge.hoge1(); // 20
hoge.hoge2(); // 210
alert(foo.a); // 210
alert(hoge.z); // 20
alert(hoge.hoge3()); // undefined
alert(hoge.hoge3.abc); // "abc is not defined"
alert(abc);
この例では、オブジェクトが3つあります。foo、fxx、そして hoge ですね。foo および fxx にプロパティをセットし、hogeのメソッドから値を変更してみてみます。
つまり...
- 他オブジェクトから値を取得できる
- 他オブジェクトのプロパティを変更できる
- プロパティにセットした値は保持される
- メソッド内で新規作成したプロパティも保持される
- メソッド内で return したものが返ってくる
- メソッド内で定義した変数にはアクセスできない
で、まったく同じことを流行の書き方で書くとこうなる
// 準備
var foo = {
x: 50,
a: 10
}
var fxx = {
x: 50,
a: 10
}
var hoge = {
hoge1: function(){
this.z = foo.a + fxx.a;
alert(this.z);
},
hoge2: function(){
foo.a = foo.a + 200;
alert(foo.a);
},
hoge3: function() {
var num = foo.a + 300;
var abc = 'variable';
return num;
}
}
// 実行
hoge.hoge1(); // 20
hoge.hoge2(); // 210
alert(foo.a); // 210
alert(hoge.z); // 20
alert(hoge.hoge3()); // undefined
alert(hoge.hoge3.abc); // "abc is not defined"
alert(abc);
Note: スパム対策が面倒なので、コメント投稿を廃止しました。以前のコメントは残します。
ご意見・ご要望はtwitter@sigwygかはてブコメントにて。