入門⑤

■オブジェクト汚染(Objectオブジェクトのprototypeの操作)

ex.
Object.prototype.hoge = function(){}; //オブジェクト汚染
var obj = {a:1};
for(var p in obj) {
console.log(p + ' ' + obj[p]);
}

出力結果
a 1
hoge function () { }


●↑の解説

ライブラリなど他の人が書いたコードのObjectクラスを操作すると、
オブジェクトを単純に走査できなくなってしまうので、
Objectクラスのprototypeをいじることはできるだけ避けたほうがいい。
このObjectクラスのprototypeをいじることを「オブジェクト汚染」と呼ぶ。




■スコープチェーン

JavaScriptの変数は、インタプリタの内部で全て特殊なオブジェクトの
プロパティとして具体化され、グローバルスコープに相当するGlobalオブジェクトと
関数スコープに相当するActivationオブジェクトが存在する。

※Javaのfor文やif文のようなローカルスコープは存在しない。


検証1.ローカル変数がない
if(true) {
var a = 3;
}
console.log(a); // 3




■Globalオブジェクト(ページのロード時に初期化)

関数以外で宣言された変数は全てGlobalオブジェクトに確保される。

Globalオブジェクトはスクリプトのどこからでも参照でき、
インタプリタの起動時に1つだけ生成され、スクリプトの実行が指示される度に初期化される。

ブラウザの場合はページがロードされたときに「window」というオブジェクトに格納される。

ex.
var a = 1;
console.log(window.a); // 1

※alertもwindowオブジェクトに格納されている



■Globalオブジェクトの初期化の手順(関数定義 → 変数定義 → 関数リテラル の順)

①読み込んだスクリプト中の、全ての変数宣言と関数定義を確認する


②関数定義と同名のプロパティを作成し、指定された内容で関数型の値を生成して格納する。
 同名のプロパティがある場合は上書きする


③変数宣言と同名のプロパティを作成し、undefinedで初期化する。
 同名のプロパティが存在する場合は何もしない


④スクリプトを実行する(関数リテラル宣言されているものはここで読み込まれる)


検証1.関数リテラル宣言される前に実行

a();
function a(){};
b() //エラー発生
var b = function(){};


↓エラーが発生しない例
a();
function a(){};
var b = function(){};
b();

console.log(typeof(a)); //function
console.log(window.a); //a()
console.log(typeof(b)); //function
console.log(window.b); //function()

※関数リテラルで宣言しても、実行時にGlobalオブジェクトとなる




■Activationオブジェクト

Activationオブジェクトは、関数を実行するたびに生成されるオブジェクトで、
関数内部の変数をプロパティとして具体化する。
Globalオブジェクトと違い、スクリプトからは直接参照できない。

ex.
function test(a,b) {
var c = a;
function d() {}
}
test(1,2); // Activationオブジェクトが生成される



■Activationオブジェクトの初期化手順(arguments生成 → 関数定義 → 変数定義 → 関数実行)

①引数と同名のプロパティを作成し、指定された値で初期化する。
 指定された個数が足りない場合は残りをundefinedで初期化する。


②argumentsプロパティを作成し、引数で指定された内容で関数型の値を生成して格納する。
 同名のプロパティが存在する場合は上書きする。


③実行する関数中の、全ての変数宣言と関数定義を確認する。


④関数定義と同名のプロパティを作成し、指定された内容で関数型の値を生成して格納する。
 同名のプロパティが存在する場合は上書きする


⑤変数宣言と同名のプロパティを作成し、undefinedで初期化する。
 同名のプロパティが存在する場合は何もしない


⑥関数を実行する


上記の動きを確認するための例

ex.
function test(a,b) {
var c = a;
function d() {}
var e = arguments[0];
var f = arguments[1];
var g = arguments[2];
var h = arguments.length;

console.log(a); // 1
console.log(b); // 2
console.log(c); // 1
console.log(d); // d()
console.log(e); // 1
console.log(f); // 2
console.log(g); // undefined
console.log(h); // 2
console.log(test); // test(a, b)
}
test(1,2);

console.log(typeof(a)); // undefined
console.log(typeof(b)); // undefined
console.log(typeof(c)); // undefined
console.log(typeof(d)); // undefined
console.log(typeof(e)); // undefined


出力結果:

1
2
1
d()
1
2
undefined
2
test(a, b)
undefined
undefined
undefined
undefined
undefined


※argumentsでは、自分自身を呼び出した関数の参照がcalleeというプロパティに格納され、
 calleeを利用することで、処理を再帰的に呼び出せます。


■関数の変数を格納するScopeプロパティ

関数内部では、[[Scope]]という特殊なプロパティがあり、
ここに変数オブジェクトのリストが格納されています。(スコープチェーンという)

※[[Scope]]は関数生成時に初期化され、その時のスコープチェーンを継承します。