- トップページ
- 特集PC技術
- コアJavaScript(ECMAScript)の図書室
- 30冊目 【JavaScript】[ECMAScript] スコープチェーン
コアJavaScript(ECMAScript)の図書室
30冊目 【JavaScript】[ECMAScript] スコープチェーン
スコープチェーンとは、変数を参照するときの方法です。
どういった方法で該当の変数が参照されているのか説明をします。
スコープチェーンの説明する前に抑えておきたいポイントが3つありますので先に説明します。
それは、関数内関数、Globalオブジェクト、Callオブジェクトです。
目次
[1] 関数内関数
スコープチェーンを理解せねばならない項目の1つ目は関数内関数のことです。
関数内関数とは書いてある字のままですが、関数の中にある関数のことです。
Javaとかだとこのような記述はできないので紛らわしいかもしれません。
ここでは、関数の中になる関数の実行方法を理解してください。
// 関数 function outside_func(){ document.writeln("関数が実行されました"); // 関数内関数 function inside_func(){ document.writeln("関数内関数が実行されました"); } // 関数内関数の実行 inside_func(); } // 関数内関数をここから直接使用する方法は以下のとおり // ここからはinside_func関数が見えないので実行できないのでエラーとなる //inside_func(); // 定義した関数の中に実行できる処理があれば実行できる outside_func();
[2] Globalオブジェクト
スコープチェーンを理解せねばならない項目の2つ目はGlobalオブジェクトです。
スクリプト全体からみた位置にある変数や関数がGlobalオブジェクトのことです。
// ここに定義された変数はGlobalオブジェクト var global_data = "グローバルデータ"; // 関数 function outside_func(){ document.writeln("関数内から参照="+global_data); // 関数内関数 function inside_func(){ document.writeln("関数内関数から参照="+global_data); } // 関数内関数の実行 inside_func(); } // global_dataはどこからでも参照できる。 // これがGlobalオブジェクト outside_func(); document.writeln("スクリプト全体から参照="+global_data);
[3] Callオブジェクト
スコープチェーンを理解せねばならない項目の3つ目はCallオブジェクトです。
Callオブジェクトとは関数呼び出しごと、内部的に自動生成されるオブジェクトのことです。
プログラムから意図的に呼び出したり、普段意識することすらありません。
この関数呼出しごと、内部的に自動生成されるという概念は重要なポイントです
定義された変数がどこから参照できるのかがポイントになります。
var global_data = "グローバルデータ"; // 関数 function outside_func(){ // callオブジェクト var outside_data = "関数のデータ"; // 関数内で参照できる変数 document.writeln("関数内から参照="+global_data); document.writeln("関数内から参照="+outside_data); // 関数内関数 function inside_func(){ // callオブジェクト var inside_data = "関数内関数のデータ"; // 関数内関数で参照できる変数 document.writeln("関数内関数から参照="+global_data); document.writeln("関数内関数から参照="+outside_data); document.writeln("関数内関数から参照="+inside_data); } // 関数内関数の実行 inside_func(); } outside_func(); // スクリプト全体から参照できる変数 document.writeln("スクリプト全体から参照="+global_data);
[4] スコープチェイン
スコープチェーンとは、変数がどの値を参照しているのか見極めるためのアクセスする順番のことです。
スクリプト全体に定義された変数がどのような値を参照しているのかが重要です。
var data1 = 10; var data2 = 100; var data3 = 1000; // 関数 function outside_func(){ // callオブジェクト var data1 = 20; var data2 = 200; // 関数内で参照できる変数 document.writeln("関数内で参照した場合"); document.writeln("data1="+data1); // 20 document.writeln("data2="+data2); // 200 document.writeln("data3="+data3); // 1000 // 関数内関数 function inside_func(){ // callオブジェクト var data2 = 300; // 関数内関数で参照した時 document.writeln("関数内関数で参照した場合"); document.writeln("data1="+data1); // 20 document.writeln("data2="+data2); // 300 document.writeln("data3="+data3); // 1000 } // 関数内関数の実行 inside_func(); } document.writeln("スクリプト全体で参照した場合"); document.writeln("data1="+data1); // 10 document.writeln("data2="+data2); // 100 document.writeln("data3="+data3); // 1000 outside_func();
同じ変数が定義されている場合に、それぞれの3つの環境によって表示される値が違うことがわかります。
スクリプト全体から参照している場合は説明はわざわざしませんが、関数内で参照した場合だけ説明だけします。
関数内で参照した場合には、「data1」と「data2」が関数内にあるためここで参照される変数が決定します。
残った「data3」はoutside_func関数内に存在しないため、外側の環境(スクリプト全体)に「data3」が存在しているか探します。
実際には「data3」がスクリプト全体の環境に存在しているためその値が表示されます。
関数内関数(inside_func)の場合には、内側からつまり、関数内関数、外側の関数、スクリプト全体の順番で変数を探します。
data3は外側の関数(outside_func)と同じようにスクリプト全体の変数(グローバル変数)を参照します。
data2は関数内関数の変数(ローカル変数)を参照して表示します。
ここで問題なのが、data1なのですが、外側で宣言しているdata1の変数を参照します。
この時、関数内関数から見て、data1という変数はローカル変数でもグローバル変数でもない変数です。
このような変数はレキシカル変数と呼ばれています。このレキシカル変数は重要な概念です。
ここでは、関数内関数から外側の関数にある変数を参照している場合にそういう呼び名があると理解しておけばよいです。
このように変数がどの値を参照しているのか理解することが重要になります。
[5] 更新履歴
日付 | 詳細 |
---|---|
2011/08/23 | コンテンツ公開 |
2012/01/30 | [4] スコープチェインのサンプルソースコードの誤りを修正 |
コメント
通りすがり
[4]スコープチェインのサンプルコード 26行目のコメントが誤っているようです。
[24] // 関数内関数で参照した時
[25] document.writeln("関数内関数で参照した場合");
×[26] document.writeln("data1="+data1); // 30
○[26] document.writeln("data1="+data1); // 20
[27] document.writeln("data2="+data2); // 300
[28] document.writeln("data3="+data3); // 1000
2012年1月29日 19:01
特集PC技術メンバー
ご連絡ありがとうございます。特集PC技術メンバーです。
指摘事項を確認致しましたところ
誤って記述しておりました。申し訳ありません。
また何かありましたら、意見・連絡等よろしくお願い致します。
2012年1月30日 17:20
コメントの投稿
トラックバックURL
http://www.isl.ne.jp/cgi-bin/mt/mt-tb.cgi/1700