「JavaScript高級プログラム設計第三版」学習ノート(六)関数とクローズド詳細

4713 ワード

一、関数宣言
1.関数の宣言文法:function funcName(){}jsは実行前に関数宣言をロードしますので、呼出後に関数を宣言してもいいです.c言語のように先に声明してから呼び出して、それを書いて実行してもいいです.この学名は「関数宣言アップ」と言います.2.関数の表現文法:var funcName=function(){}この方法は、まず匿名関数を作成し、関数のアドレスを変数に伝えます.だからfuncNameを呼び出す前に、先に関数を書いてください.ステートメント文法のように先に使ってはいけません.後で声明します.
二、作用ドメインチェーンの作成過程
//   
function compare(value1,value2){
	if(value1value2){
		return 1;
	}else{
		return 0;
	}
}
var result=compare(3,4);
1.関数の実行
(1)関数compareが初めて実行されると、解像器はそれのために実行環境を作成し、その作用ドメインチェーンを完成する.(2)this、argmentsおよび他の名前付きパラメータの値初期化関数を用いたアクティブオブジェクト.(3)作用ドメインチェーンにおいて、第一層外部関数の活動対象は第二位であり、大域実行環境における活動対象は最後である.(4)関数実行中に変数を読み込み、書き込みするためには、作用ドメインチェーン内で変数を検索する必要があります.
2.作用ドメインチェーンの生成
(1)compareを作成する時、グローバル変数を含む作用ドメインチェーンを作成しておきます.この時、作用ドメインチェーンの中にはアクティブなオブジェクトが一つしかありません.活動対象にはthis、compare、reultが含まれています.(2)compareを呼び出すと、もう一つの活動対象を作成し、その活動対象を作用ドメインチェーンの先端に置き、その前にグローバル変数を含む活動対象を第二に移動します.新しい活動対象はvalue 1とvalue 2が含まれています.(3)compreの実行が完了すると、(2)に作成された活動対象(value 1とvalue 2を含む)は破棄され、compreの作用ドメインチェーンはグローバル変数活動対象のみとなります.
三、閉包する
1.クローズドの概念
(1)他の関数のスコープ内の変数にアクセスできる関数を指します.閉じたパケットを作成する一般的な方法は、関数の内部に別の関数を作成することです.(2)次の例では、returnの匿名関数Aは、別の関数compreの局所変数atrNameを使用しているので、クローズドである.
//   
//               ,  array.sort    。
function compare(attrName){
	return function(object1,object2){//    A
		if(object1[attrName]object2[attrName]){
			return 1;
		}else{
			return 0;
		}
	}
}
var func=compare("age");
var result=func({age:14},{age:15});
alert(result);//-1
(3)上記の例の匿名関数Aはcompreの外部に戻って実行されるが、Aの作用領域チェーンにはcompreの局所変数が含まれている.
2.クローズド形成の原因
(1)匿名関数Aがcompre内部にあるからこそ、Aの作用ドメインチェーンにはcompreで作成されたアクティブオブジェクトが含まれ、compreの局所変数が使用される.まだ分からない場合は、「作用ドメインチェーンの生成」をよく読んで、次の内容を読んでください.(2)匿名関数Aがcompareから戻ってきたら、その作用ドメインチェーン内に二つの活動対象があります.最初はcompreの活動対象です.二つ目はグローバル活動の対象(compre、func、reultを含む)です.ここでthisはまず言わないでください.(3)より重要な問題(クローズドが作動できるコア条件)は、compreが実行された後、匿名関数Aに戻りfuncを与えた後、自分で作成した活動対象(atrNameを含む)は廃棄されていません.funcの作用領域チェーンにはまだこの活動対象を引用しているからです.これはjsメモリ回収メカニズムによって決定されたもので、正確には、compareが実行された後、その実行環境、作用域チェーンが破壊されます.しかし、スコープは、実際には行列にすぎません.そこには、アクティブなオブジェクトを指すポインタがあります.活動対象が廃棄される前提は、すべての対象を指す指針が廃棄されたことです.したがって、funcの作用ドメインチェーンには、compre活動の対象を指すポインタが含まれている場合、compreの活動対象はメモリに保持されます.(4)func実行が完了すると、funcが作成した活動対象(age 14とage 15を含む)が破棄され、compreの活動変数が破壊されます.
3.クローズドのメリットとデメリット
(1)とても使いやすいです.(2)分かりにくい、特に階層が多い場合.(3)クローズドは、通常の関数よりメモリの占有量が多い.ですから、やむを得ない時には、クローズドバッグを使わないでください.クローズドを使っても、レイヤーが多すぎないようにしてください.
四、クローズドと親レベル変数
1.最後の値
(1)クローズドされたロールフィールドチェーンには、各レベルのアクティビティオブジェクトが保存されており、これらのオブジェクトを介して外部関数の変数が使用されます.これは閉包実現の基本原理です.(2)基本原則に基づき、外部関数が実行された後、外部関数の活動対象には、局所変数の最後の値が保存されています.
//   
function box(){
	var arr=[];
	for(var n=0;n<10;n++){
		arr.push(function(){
			alert(n);	
		});	
	}
	return arr;
}
var funcs=box();
funcs[0]();//10
funcs[9]();//10
(3)上記の例では、alertは常に10である.boxが実行された後に、一つのクローズド・グループに戻ってきました.そして、各クローズドはnを使用できますが、nの値は思ったより0から9までではなく、10です.原因は前に説明しました.各クローズド・パケットalertを配列内のインデックスから出すために、別の匿名関数を作成し、強制的に実行することができます.
//   
function box(){
	var arr=[];
	for(var n=0;n<10;n++){
		arr[n]=function(num){
			return function(){
				alert(num);	
			}
		}(n);
	}
	return arr;
}
var funcs=box();
funcs[0]();//0
funcs[9]();//9
(4)関数の強制実行
(補足知識):下記の例は関数強制実行(以下はv 8エンジンで実験した結果)です.
<1>強制実行の戻り値を変数で保存しないと、関数体は括弧で囲まなければなりません(正常1).関数が宣言関数であれば、強制的に実行されません(異常1).匿名関数であれば、構文エラー(異常2)が発生します.
<2>強制実行の戻り値を変数によって保存すると、関数は匿名であり、関数が包含されていないかは問題ない(正常2−5).
<3>「正常1」をクローズドと考える人が多いが、実は正しくない.これは匿名関数の強制実行にすぎず、クローズドとはあまり関係がなく、クローズドデザインでは上記の問題を避けるために、しばしばこの強制実行を使用しているだけです.
//   
//  1
(function(i,j){
	alert(i+j);//3
})(1,2);
//  1
function abc(i,j){
	alert(i+j);//  alert,       。
}(1,2);
//  2
function(i,j){
	alert(i+j);	
}(1,2);//Unexpected token (


//  2
var b=(function(i,j){
	alert(i-j);//-1
	return i-j;	
})(1,2);
alert(b);//-1
//  3
var a=function(i,j){
	alert(i+j);//3	
}(1,2);
alert(a);//undefined


//  4
var c=(function func(i,j){
	alert(i-j);//-1
	return i-j;	
})(1,2);
alert(c);//-1
  5
var d=function func(i,j){
	alert(i-j);//-1
	return i-j;	
}(1,2);
alert(d);//-1
五、閉包とthisの針
1.thisポインタは、関数実行時に環境バインディングを関数に基づいて実行します.言い換えれば、thisはスコープと直接関係がありません.関数はどこにありますか?2.クローズドバッグはどこで実行しますか?誰も言えません.thisとは何を指しますか?運行期間も見ます.ですから、クローズドにthisを使う時は特に注意してください.(このようなテーマは面接で多いです.A社2015校のweb募集前の問題の中で一つに出会いました.)
//   
var name="window";
var obj={
	name:"obj",
	getName:function(){
		return function(){
			return this.name;	
		}
	},
	getName1:function(){
		var _this=this;
		return function(){
			return _this.name;	
		}
	}
}
alert(obj.getName()());//window
alert(obj.getName1()());//obj