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); // 110alert(foo); // 10
関数 hoge() 内で弄った変数の値は、hoge() 内でのみ有効。
// 準備var foox = 50;var fooa = 10;var hoge = function(foo){var foob = foo + 100;alert(foox); // 50alert(foob); // 110};// 実行hoge(fooa);alert(fooa); // 10alert(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(); // 20hoge.hoge2(); // 210alert(foo.a); // 210alert(hoge.z); // 20alert(hoge.hoge3()); // undefinedalert(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(); // 20hoge.hoge2(); // 210alert(foo.a); // 210alert(hoge.z); // 20alert(hoge.hoge3()); // undefinedalert(hoge.hoge3.abc); // "abc is not defined"alert(abc);
Note: スパム対策が面倒なので、コメント投稿を廃止しました。以前のコメントは残します。
ご意見・ご要望はtwitter@sigwygかはてブコメントにて。