入門⑤
■オブジェクト汚染(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]]は関数生成時に初期化され、その時のスコープチェーンを継承します。