この記事の内容
匿名関数の紹介
クロージャ
変数スコープ
関数外から関数内のローカル変数にアクセス
クロージャを使ってプライベートメンバーを実装
の紹介
closure パッケージは匿名関数を使用して実装されます。クロージャは、埋め込み関数によって生成される保護された変数空間です。 「保護された変数」という考え方は、ほぼすべてのプログラミング言語で見られます。
まず JavaScript のスコープを見てみましょう:
JavaScript には関数レベルのスコープがあります。これは、関数内で定義された変数には関数の外部からアクセスできないことを意味します。
JavaScript のスコープは字句的にスコープされます。これは、関数が呼び出されたスコープではなく、関数が定義されているスコープで実行されることを意味します。これは JavaScript の大きな特徴であり、後で説明します。
これら 2 つの要素を組み合わせると、変数を匿名関数でラップすることで変数を保護できます。次のようなクラスのプライベート変数を作成できます:
var baz;
(function() {
var foo = 10;
var bar = 2;
baz = function() {
return foo * bar;
};
} )();
baz();
baz は匿名関数の外で実行されているにもかかわらず、foo と bar にアクセスできます。
説明:
1、1 行目、baz はグローバル変数です。
2、3 行目から 9 行目は、匿名関数を定義します。 、4 行目と 5 行目、foo と bar は匿名関数内のローカル変数です。6 行目から 8 行目は、匿名関数内で匿名関数を定義し、それをグローバル変数 baz に割り当てます。バズを呼ぶ。 「alert(baz());」に変更すると、20 が表示されます;
5. 論理的に言えば、foo と bar は匿名関数の外からはアクセスできませんが、現在はアクセス可能です。
クロージャを説明する前に、まず匿名関数を理解しましょう。
匿名関数
匿名関数は、関数名を定義する必要のない関数です。匿名関数はラムダ式と同じものです。唯一の違いは文法形式です。ラムダ式はさらに一歩進んだものです。本質的に、それらの機能はメソッド、つまりインライン メソッドを生成することです。つまり、関数定義を省略して関数本体を直接記述します。
ラムダ式の一般形式:
(入力パラメータ) => {statement;}
ここで:
パラメータ リスト。複数のパラメータ、1 つのパラメータ、またはパラメータなしの可能性があります。 。パラメータは暗黙的または明示的に定義できます。
関数本体である式またはステートメント ブロック。
上記コード6行目から8行目は関数名が無く、厳密には構文は異なりますが目的は同じです。
例 1:
コードをコピーします
var foo = 10;
var bar = 2;
return foo
};
var baz2 =
alert(); ;
説明:
1、baz1 は baz2 とまったく同じですが、baz2 と比較すると、baz1 は関数定義を省略し、関数本体を直接使用しています。非常に単純に見えます。
クロージャ
変数スコープ
例 2: グローバル変数は関数内でアクセスできます。
コードをコピーします
コードは次のとおりです。
var baz = 10; 🎜>function foo() {
alert(baz); } foo(); これは問題ありません。
例 3: 関数内のローカル変数には関数の外部からアクセスできません。
コードをコピー
コードは次のとおりです。
function foo() {
さらに、関数内で変数を宣言する場合は、var キーワードを使用する必要があります。それ以外の場合は、グローバル変数が宣言されます。
例 4:
コードをコピー
コードは次のとおりです:
function foo() {
bar = 20;
} alert(bar); 関数の外部から関数内のローカル変数にアクセスする🎜> 実際の状況では、関数内のローカル変数を関数の外から取得する必要があります。まず例 5 を見てみましょう。
例 5:
コードをコピー
コードは次のとおりです。
関数 foo() {
var a = 10;
関数 bar() {
a *= 2;
bar();
}
var baz = foo();
alert(baz);
a は foo で定義されているため、bar にもアクセスできます。 foo内で定義されています。さて、foo の外で bar を呼び出すにはどうすればよいでしょうか?
例 6:
function foo() {
var a = 10;
function bar() {
a *= 2;
return bar; >}
var baz = foo();
alert(baz());
var blat = foo( );
alert(blat());
注:
1 は外部からアクセスできるようになりました。 🎜>2、JavaScript のスコープは語彙的です。 a は、foo が呼び出されるスコープ内ではなく、それが定義されている foo 内で実行されます。 foo で bar が定義されている限り、foo の実行が終了しても、foo で定義された変数 a にアクセスできます。つまり、「var baz = foo()」が実行された後、foo は実行され、a は存在しないはずですが、後で baz が呼び出されたときに、a がまだ存在していることがわかります。これは JavaScript の特徴の 1 つであり、呼び出しを実行するのではなく、定義に基づいて実行されます。
このうち、「var baz = foo()」は bar 関数への参照であり、「var blat= foo()」は別の bar 関数への参照です。
クロージャを使用してプライベート メンバーを実装します。
次に、オブジェクト内でのみアクセスできる変数を作成する必要があります。クロージャは、特定の関数のみがアクセスできる変数を作成でき、それらの関数の呼び出し後も保持されるため、完璧です。
プライベート プロパティを作成するには、コンストラクターのスコープで関連する変数を定義する必要があります。これらの変数には、特権メソッドによるものも含め、スコープ内で定義されたすべての関数からアクセスできます。
例 7:
コードをコピー
コードは次のとおりです:
// 特権メソッド
this.getIsbn = function() {
returnisbn;
};
this.setIsbn = function(newIsbn); 🎜>if (!checkIsbn(newIsbn)) throw new Error('書籍: 無効な ISBN.');
this.getTitle = function() {
returnタイトル;
};
this.setTitle = function(newTitle) {
title = newTitle || 'タイトルが指定されていません。';
this.getAuthor = function() {
return author;
};
this.setAuthor = function(newAuthor) {
author = newAuthor || '著者が指定されていません。'
};
this.setIsbn(newIsbn);
this.setAuthor(newAuthor);
; 🎜>Book .prototype = {
display: function() {
// TODO
}
};
説明:
1、変数isbn、title、authorをこの代わりにvarで宣言すると、それらはBookコンストラクター内にのみ存在することになります。 checkIsbn 関数もプライベートであるため、同じことが言えます。
2. プライベート変数およびメソッドにアクセスするメソッドは、Book 内で宣言する必要があるだけです。これらのメソッドは特権メソッドと呼ばれます。これらはパブリック メソッドですが、getIsbn、setIsbn、getTitle、setTitle、getAuthor、setAuthor (値のゲッターとコンストラクター) などのプライベート変数やプライベート メソッドにアクセスできるためです。
3. オブジェクトの外部にあるこれらの特権メソッドにアクセスするには、これらのメソッドの前に this キーワードを追加します。これらのメソッドは Book コンストラクターのスコープ内で定義されているため、プライベート変数、isbn、title、author にアクセスできます。ただし、これらの特権メソッドでisbn、title、author変数を参照する場合、thisキーワードは使用されず、直接引用されます。それらは非公開だからです。
4. プライベート変数への直接アクセスを必要としないメソッド (表示など、Book.prototype で宣言されたものなど)。プライベート変数に直接アクセスする必要はありませんが、get*、set* の導入を通じてアクセスします。
5、この方法で作成されたオブジェクトは、真にプライベートな変数を持つことができます。他のユーザーは Book オブジェクトの内部データに直接アクセスすることはできず、エバリュエーターを通じてのみアクセスできます。このようにして、すべてを制御できます。
しかし、このアプローチの欠点は次のとおりです。
「オープンドア」オブジェクト作成モードでは、すべてのメソッドがプロトタイプ プロトタイプ オブジェクト内に作成されるため、オブジェクト インスタンスがいくつ生成されても、これらのメソッド メモリ内にはコピーが 1 つだけあります。
このセクションのアプローチでは、新しいオブジェクト インスタンスが生成されない場合、プライベート メソッド (checkIsbn など) と特権メソッド (getIsbn、setIsbn、getTitle、setTitle、getAuthor、setAuthor など) ごとに 1 つ生成されます。新しいコピー。
したがって、このセクションの方法は、プライベート メンバーが本当に必要な状況での使用にのみ適しています。さらに、このアプローチは継承を助長しません。