ホームページ >ウェブフロントエンド >jsチュートリアル >Javascriptの関数、再帰、クロージャの使い方を詳しく解説(実行環境、変数オブジェクト、スコープチェーン)_基礎知識

Javascriptの関数、再帰、クロージャの使い方を詳しく解説(実行環境、変数オブジェクト、スコープチェーン)_基礎知識

WBOY
WBOYオリジナル
2016-05-16 17:34:15919ブラウズ

関数式

1. JavaScript で関数を定義するには 2 つの方法があります:

1-1. 関数宣言:

コードをコピー コードは次のとおりです。 >
function funcName(arg1,arg2,arg3){
//関数本体
}

①name属性:関数名を読み出すことができます。非標準のブラウザのサポート: FF、Chrome、Safari、Opera。
②関数宣言のプロモーション: コードを実行する前に関数宣言が読み取られることを意味します。つまり、関数呼び出しは関数宣言の前に配置できます。

1-2. 関数式:

コードをコピー コードは次のとおりです。 >
var funcName = function(arg1,arg2,arg3){
//関数本体
};


①匿名関数(匿名関数、またはラムダ関数) : function キーワードの後に​​識別子がなく、name 属性値が空の文字列です。匿名関数は、関数が値として使用されるときはいつでも使用できます。
②他の式と同様、関数式も使用前に値を代入する必要があるため、「関数宣言の促進」のような効果はありません。
③ECMAScript の無効な関数構文:


if判定
内の関数宣言が重複しています
if(条件){ functionsayHi(){

alert("こんにちは!");
}
} else {
functionsayHi(){
alert( "Yo!");
}
}


ブラウザーの JavaScript エンジンはエラーの違いを修正します。ほとんどのブラウザーは条件を無視して 2 番目のステートメントを返します。FF は条件を返します。条件は true の場合、最初のステートメントを返します。

関数式を使用して解決および実装します:


if判定関数式

varsayHi;if(condition){

sayHi = function(){
alert("Hi!");
}
} else {
sayHi = function (){
alert("Yo!");
}
}


2. 再帰
が形成される関数です。自分自身を名前で呼ぶことによって。

function fastial(num){ //A古典的な再帰 階乗関数
if (num return 1;
} else {
return num *階乗(num-1);
}
}


①以下のコードでこの関数を呼び出すとエラーが発生します:


var anotherFactory = fastial;
factorial = null;
alert(anotherFactorial(4));


保存後変数anotherFactoryにfactorial()関数を追加します。factorial変数をnullに設定すると、関数は参照されなくなり、anotherFactorial(4)でfactorial()関数を実行する必要があるため、エラーが発生します。
argument.callee (実行される関数へのポインタ) を使用して解決します:


解決策

関数階乗(num){ if (num return 1;
} else {
return num * argument.callee(num-1);
}
}

var anotherFactorial = Factorial;factorial = null;

alert(anotherFactorial(4)) //24


非厳密モードでは、再帰関数を使用する場合、関数名の代わりに argument.callee を使用する方が安全です。
厳密モードでは、argument.callee を使用するとエラーが発生します。 関数式を使用できます。関数宣言の代わりに:

コードをコピー コードは次のとおりです:

関数式は関数を置き換えます宣言

var fastial = function f(num){
if (num return 1;
} else {
return num * f(num-1);
}
}


4. 終了

は、別の関数のスコープ内の変数にアクセスできる関数を指します。 (一般的な形式は関数の入れ子です)

コードをコピー コードは次のとおりです:

関数wai(pro ){
return function(obj1,obj2){
var val1 = obj1[pro];
var val2 = obj2[pro];
if(val1 return - ; 🎜>}


匿名関数を返す場合、関数のアクティブ オブジェクトとグローバル変数オブジェクトを含むように匿名関数のスコープ チェーンが初期化されます。つまり、匿名関数には wai() 関数のスコープが含まれます。
各関数が呼び出されると、実行環境、変数オブジェクト、および対応するスコープ チェーンが作成されます。


4-1. 実行環境と範囲

環境と呼ばれる実行環境の実行コンテキストは、関数がアクセスできる変数やその他のデータを定義し、それぞれの動作を決定します。
①各実行環境には変数オブジェクトがあり、環境で定義されたすべての変数と関数が保存されます。このオブジェクトにはコードからアクセスできませんが、パーサーはデータ処理時にバックグラウンドでこのオブジェクトを使用します。 グローバル変数オブジェクトは最も周辺的な実行環境です。これは Web ブラウザではウィンドウ オブジェクトとみなされ、すべてのグローバル オブジェクトと関数はウィンドウ オブジェクトのプロパティとメソッドによって作成されます。

実行環境内のコードが実行されると、その環境は破棄され、そこに保存されている変数や関数定義も破棄されます。 ②コードが環境内で実行されると、実行環境がアクセスできるすべての変数と関数に順序よくアクセスできるように、変数オブジェクトのスコープ チェーンが作成されます。

スコープチェーンのフロントエンドは常に、現在実行されているコードが配置されている環境の変数オブジェクトです。環境が関数の場合、アクティブ オブジェクトは変数オブジェクトとして使用されます。

アクティブなオブジェクトには、最初は引数オブジェクトという変数が 1 つだけ含まれています。
スコープチェーン内の次の変数オブジェクトは包含環境から取得され、次の変数オブジェクトは次の包含環境から取得され、グローバル実行環境に継続されます。

③識別子の解析: 前の段落から始まり、スコープチェーンに沿ってレベルごとに識別子を検索するプロセス。 【見つからない場合は通常エラーになります】


4-2. 関数を作成して実行する場合:

コードをコピーします

function Compare(val1,val2){ if(val1 return -1; }else if(val1>val2){ 1 を返す;
}else{
0 を返す;
};
}
var result = Compare(5, 10);


①関数compare()を作成すると、グローバル変数オブジェクトを事前に含むスコープチェーンが作成され、内部の[[scope]]属性に格納されます。
②ローカル関数compare()の変数オブジェクトは関数実行中のみ存在します。
関数が呼び出されると、実行環境が作成され、関数の [[scope]] 属性内のオブジェクトをコピーすることによって実行環境のスコープ チェーンが構築されます。
③compare()などの関数を初めて呼び出すと、これと引数、val1、val2を含むアクティブオブジェクトが作成されます。
④グローバル実行環境の変数オブジェクト(this、result、compareを含む)は、compare()実行環境のスコープチェーンの2番目にあります。
⑤スコープチェーンは本質的に変数オブジェクトを指すポインタのリストであり、参照するだけで実際には変数オブジェクトを含みません。
⑥関数内で変数にアクセスするたびに、スコープチェーン内で対応する名前の変数が検索されます。

4-3. クロージャのスコープチェーン

別の関数内で定義された関数は、その関数を含むアクティブなオブジェクトをそのスコープ チェーンに追加します。
①関数オブジェクトを null に代入することは、関数のスコープ チェーンが破棄されると、そのスコープ チェーン (グローバル スコープを除く) も安全に破棄されます。
②クロージャはそれを含む関数のスコープを持つため、他の関数よりも多くのメモリを消費します。

4-4. クロージャと変数

スコープチェーンの副作用: クロージャは、それを含む関数内の変数の最後の値しか取得できません。

コードをコピー コードは次のとおりです。

function createFunctions(){
var result = new Array();
for (var i=0; i result[i] = function(){
return i;
};
}
Return result;
}

①createFunctions()関数を実行し、結果の配列にクロージャを10個代入し、結果の配列を返します。各クロージャは独自のインデックスを返しますが、実際にはすべて 10 を返します。
createFunctions() 関数のアクティブ オブジェクトは各関数のスコープ チェーン (クロージャ) に格納されているため、同じ変数 i を参照します。createFunctions 関数が実行されると、i の値は 10 になります。クロージャ バッグの中の i もすべて 10 です。
②解決策は、クロージャを使用せずに匿名関数を作成し、そのパラメータに i 値を割り当てることです:
コードをコピーコードは次のとおりです:

function createFunctions(){
var result = new Array();
for (var i=0; i result[i] = function(num){
🎜> }


ループするたびに 1 回実行される匿名関数を作成します。ループするたびに関数を囲む i 値を使用します。パラメータとしてループし、それを無名関数に格納します。関数パラメータは参照ではなく値によって渡されるため、各匿名関数の num 値は、ループを通過するたびに i 値のコピーになります。


4-5.このオブジェクト

このオブジェクトは、関数の実行環境に基づいて実行時にバインドされます。 グローバル関数では、これは window に相当します。関数がオブジェクトによって呼び出される場合、これはオブジェクトです。

匿名関数の実行環境はグローバルであり、その this オブジェクトは通常 window を参照します。 call() または apply() を通じて関数の実行環境を変更する場合、this はそのオブジェクトを指します。 ①各関数が呼び出されると、thisとargumentの2つの特殊変数が自動的に取得されます。内部関数がこれら 2 つの変数を検索する場合、有効期限が切れたアクティブ オブジェクトまでのみ検索され、外部関数のこれら 2 つの変数にアクセスすることはできません。 ただし、this オブジェクトをクロージャがアクセスできる変数の外部スコープに格納することで、クロージャはオブジェクトにアクセスできるようになります。




コードをコピー

コードは次のとおりです:

Closure accesses the this object of the external function

var name = "The Window";

var object = {
name : "My Object",

getNameFunc: function(){
var that = this;
return function(){
return that.name;
};
}
};

alert(object.getNameFunc()()); //"MyObject"


  The argument object surrounding the function can also be accessed by the closure through this method.

5. Convert function declaration to function expression

JavaScript puts the function keyword at the beginning of the function declaration, but the function declaration cannot be followed by parentheses, so function(){......}(); will cause an error.
To convert a function declaration into a function expression, add a pair of parentheses to the function declaration:

Copy code Code As follows:

(function(){
//Block-level scope
})();
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。