ホームページ > ウェブフロントエンド > jsチュートリアル > Javascriptのクロージャを詳しく解説_基礎知識

Javascriptのクロージャを詳しく解説_基礎知識

WBOY
リリース: 2016-05-16 16:24:21
オリジナル
969 人が閲覧しました

前書き: これはまだ紹介記事です。 Javascript には、オブジェクト、プロトタイプの継承、クロージャなど、非常に重要な言語機能がいくつかあります。その中でもクロージャは、従来の静的言語 C/C を使用するプログラマ向けの新しい言語機能です。この記事では、JavaScript クロージャの言語機能を紹介する例から始め、それをいくつかの ECMAScript 言語仕様と組み合わせて、読者がクロージャをより深く理解できるようにします。

注: この記事は入門記事であり、サンプル資料はインターネットから収集したものです。専門家であれば、この記事に関する技術的な提案や意見を提供していただけます。この記事では Javascript について説明します。JavaScript に抵抗がある場合は、迂回してください。

クロージャとは
クロージャとはクロージャのことで、静的言語にはない新しい機能です。しかし、クロージャは理解するのが難しいほど複雑なものではありません。つまり、クロージャは次のとおりです。

クロージャは関数のローカル変数のコレクションですが、これらのローカル変数は関数が戻った後も存在し続けます。
クロージャとは、関数が戻った後に関数の「スタック」が解放されないことを意味し、これらの関数スタックはスタック上ではなくヒープ上に割り当てられることも理解できます
。 関数内で別の関数を定義すると、クロージャーが生成されます
上記の 2 番目の定義は、最初の定義の主語、述語、目的語を抽出した最初の補足説明です。クロージャは関数の「ローカル変数」の集合です。このローカル変数は関数が戻った後にアクセスできるというだけです。 (これは正式な定義ではありませんが、クロージャを理解するにはこの定義の方が役立つはずです)

ローカル変数として、関数内のコードからアクセスできます。これは静的言語と変わりません。クロージャとの違いは、関数の実行が終了した後も、関数の外部のコードからローカル変数にアクセスできることです。これは、関数がクロージャを指す「参照」を返すか、この「参照」を外部変数に割り当てて、クロージャ内のローカル変数が外部コードからアクセスできるようにする必要があることを意味します。もちろん、この参照を含むエンティティはオブジェクトである必要があります。JavaScript では、基本型を除いて、その他すべてがオブジェクトであるためです。残念ながら、ECMAScript には、クロージャ内のローカル変数にアクセスするための関連メンバーやメソッドが提供されていません。しかし、ECMAScript では、関数オブジェクトに定義された内部関数 (内部関数) が、この仕組みを通じて、次の方法で外部関数のローカル変数にアクセスできます。

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

関数 挨拶(名前) {
var text = 'Hello' // ローカル変数
; // 呼び出されるたびにクロージャが生成され、内部関数オブジェクトが呼び出し元に返されます
戻り関数() { アラート(テキスト) }
}
var SayHello=greeting("閉店");
SayHello() // ローカル変数 text
はクロージャを通じてアクセスされます

上記のコードの実行結果は次のようになります: Hello Closure。これは、sayHello() 関数は、挨拶関数の実行後もその中で定義されたローカル変数テキストにアクセスできるためです。

これがクロージャの伝説的な効果です。クロージャには、シングルトン、パワー コンストラクター、クロージャの使用と切り離せない他の Javascript モードなど、JavaScript のさまざまなアプリケーション シナリオとモードがあります。

ECMAScript クロージャ モデル
ECMAScript はクロージャをどのように実装しますか?さらに詳しく知りたい方は、研究用に ECMAScript 仕様を入手してください。ここでは簡単な説明のみを行います。内容もインターネットから入手できます。

ECMAscript スクリプトの関数が実行されている場合、各関数の関連付けには実行コンテキスト シーン (実行コンテキスト) があり、この実行コンテキスト シーンには 3 つの部分が含まれます。

語彙環境
変数環境
このバインディング
3 番目のポイントであるこのバインディングはクロージャとは関係がないため、この記事では説明しません。文法環境は、関数の実行中に使用される変数識別子を解析するために使用されます。文法環境は、環境レコード (環境再コード) と外部参照 (ポインター) という 2 つの重要なコンポーネントを含むオブジェクトとして想像できます。環境レコードには、関数内で宣言されたローカル変数とパラメーター変数が含まれており、外部参照は外部関数オブジェクトのコンテキスト実行シナリオを指します。グローバル コンテキスト シーンにおけるこの参照の値は NULL です。このようなデータ構造は、各参照が外側のコンテキスト シーンを指す一方向リンク リストを形成します。

たとえば、上記の例のクロージャー モデルは次のようになります。sayHello 関数が最下層にあり、上位層が挨拶関数、最外層がグローバル シーンになります。以下に示すように、sayHello が呼び出されると、sayHello はコンテキスト シーンを通じてローカル変数テキストの値を検索するため、画面上のダイアログ ボックスに「Hello Closure」が表示されます。変数環境 (VariableEnvironment) の関数です。と文法環境は基本的に似ています。具体的な違いについては、ECMAScript 仕様ドキュメントを参照してください。

クロージャーのサンプルシーケンス
以前は、JavaScript クロージャとは何か、およびクロージャが Javascript でどのように実装されるかを大まかに理解しました。以下に、いくつかの例を通してクロージャをより深く理解するのに役立ちます。以下に 5 つの例を示します。これらの例は JavaScript Closures For Dummies (ミラー) からのものです。 例 1: クロージャ内のローカル変数はコピーではなく参照です

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

関数say667() {
// 最終的にクロージャ内に収まるローカル変数
var num = 666;
var SayAlert = function() {alert(num) }
; 番号 ;
SayAlert を返します;
}

var SayAlert = Say667();
SayAlert()

したがって、実行結果は 666 ではなく 667 になるはずです。

例 2: 複数の関数は同じ関数内で定義されているため、同じクロージャをバインドします。

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

関数 setupSomeGlobals() {
// 最終的にクロージャ内に収まるローカル変数
var num = 666;
// 関数への参照をグローバル変数として保存します
gAlertNumber = function() {alert(num) }
gIncreaseNumber = function() { 数値 }
gSetNumber = function(x) { num = x }
}
setupSomeGlobals(); // 3 つのグローバル変数に値を代入します
gAlertNumber() //666
gIncreaseNumber();
gAlertNumber() // 667
gSetNumber(12);//
gAlertNumber();//12

例 3: ループ内で関数を割り当てる場合、これらの関数は同じクロージャにバインドされます

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

関数 buildList(リスト) {
var result = [];
for (var i = 0; i var item = 'item' list[i];
result.push( function() {alert(item ' ' list[i])} );
}
結果を返します;
}
関数 testList() {
var fnlist = buildList([1,2,3]);
// 混乱を避けるためだけに j を使用します - i
を使用することもできます for (var j = 0; j fnlist[j]();
}
}

testList の実行結果は、item3 の未定義ウィンドウが 3 回ポップアップします。これは、これら 3 つの関数が同じクロージャにバインドされており、item の値が最後の計算結果であるためですが、ループから抜け出すと、 i の値は 4 なので、リスト [4] の結果は未定義です。

例 4: 外部関数のすべてのローカル変数は、この変数が内部関数の定義後に宣言された場合でも、クロージャ内にあります。

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

関数sayAlice() {
var SayAlert = function() {alert(alice) }
; // 最終的にクロージャ内に収まるローカル変数
var alice = 'こんにちは、アリス';
SayAlert を返します;
}
var helloAlice=sayAlice();
こんにちはアリス();

実行結果は「Hello Alice」のポップアップウィンドウです。ローカル変数が関数sayAlertの後に宣言されている場合でも、ローカル変数には引き続きアクセスできます。

例 5: 関数が呼び出されるたびに新しいクロージャーを作成します

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

function newClosure(someNum, someRef) {
// 最終的にクロージャ内に収まるローカル変数
var num = someNum;
var anArray = [1,2,3];
var ref = someRef;
戻り関数(x) {
num = x;
anArray.push(num);
alert('num: ' num
'nanArray ' anArray.toString()
'nref.someVar ' ref.someVar);
}
}
Closure1=newClosure(40,{someVar:'クロージャ 1'});
Closure2=newClosure(1000,{someVar:'クロージャ 2'});

クロージャ1(5); // num:45 anArray[1,2,3,45] ref:'someVarクロージャ1'
Closure2(-10);// num:990 anArray[1,2,3,990] ref:'someVar Closure2'

休業の申請
シングルトン:

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

var singleton = function () {
var privateVariable;
関数 privateFunction(x) {
...privateVariable...
}

戻り値 {
firstMethod: function (a, b) {
...privateVariable...
}、
SecondMethod: 関数 (c) {
...privateFunction()...
}
};
}();

このシングルトンはクロージャを通じて実装されます。プライベート メンバーとメソッドのカプセル化はクロージャによって完了します。匿名の main 関数はオブジェクトを返します。オブジェクトには 2 つのメソッドが含まれており、メソッド 1 はプライベート変数にアクセスでき、メソッド 2 は内部プライベート関数にアクセスできます。注意が必要なのは、匿名 main 関数の最後の「()」です。この「()」がないとシングルトンを生成できません。匿名関数は一意のオブジェクトのみを返すことができ、他の場所から呼び出すことができないためです。これは、クロージャを使用してシングルトンを生成する方法です。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート