ホームページ ウェブフロントエンド jsチュートリアル JavaScript のアドレッシング、クロージャ、オブジェクト モデル、および関連する問題の詳細_JavaScript スキル

JavaScript のアドレッシング、クロージャ、オブジェクト モデル、および関連する問題の詳細_JavaScript スキル

May 16, 2016 pm 06:53 PM
javascript 閉鎖

JS は動的言語であるため、JS のアドレス指定は C のようにコンパイル後に決定されるのではなく、オンサイトのアドレス指定になります。さらに、JS では this ポインターが導入されましたが、これはパラメーターとして関数に「暗黙的に」渡されるため、非常に厄介なものです。まず、「スコープ チェーン」トピックの例を見てみましょう:
var testvar = 'window property';
var o1 = {testvar:'1', fun:function(){alert('o1: 'この .testvar);}};
var o2 = {testvar:'2', fun:function(){alert('o2: ' this.testvar);}}; // '1'
o2.fun(); // '2'
o1.fun.call(o2); // '2' 興味深いですね。それは?実際、すべての興味深く奇妙な概念は 1 つの問題に要約でき、それは対処することです。
単純な変数のアドレス指定
JS のスコープは静的ですか?それとも動的ですか?
残念なお知らせですが、JS は静的にスコープされています。つまり、変数のアドレス指定は、Perl のような動的スコープの言語よりもはるかに複雑です。次のコードは、プログラミング言語の原則の例です。 ');
04| 関数 f2(){var x = 2; f2() }; >f1 は eval を使用して動的に定義されますが、出力は 1 で、pascal や ada とまったく同じです。別の例もプログラミング言語の原則から来ています:
function big2(){
var x = 1;
function f2(){echo(x)}; //x の値を使用して出力を生成します。
関数 f3(){var x = 3;f4(f2)};
関数 f4(f){var x = 4;f()};
f3(); 🎜 >big2();//出力 1: 深いバインディング; 出力 4: 浅いバインディング; 出力 3: 特別なバインディング
出力は 1 のままで、JS が静的スコープであるだけでなく、深いバインディングであることを示します。今、何かが間違っています...
ARI の概念
関数 (特に Ada などの入れ子関数を許可する言語) の実行時の複雑なアドレス指定の問題を説明するために、次のように定義されています。書籍「プログラミング言語の原則」「ARI」:
関数アドレス
ローカル変数
リターン アドレス
ダイナミック リンク
スタティック リンク
を含む、スタック上のいくつかのレコードです。ここで、動的リンクは常に関数の呼び出し元を指します (たとえば、b が実行されるときに a が呼び出され、a の ARI では動的リンクが b を指します)。 a が定義されているため、関数はルート付きツリーとして構成されており、要約後はすべての静的リンクがホスト (ウィンドウなど) を指すことになります (コメント後の出力)。 = 'ホスト内の x';
関数 a(){echo(x)};
関数 b(){var x = 'b 内の x';echo(x)}; ){var x = 'c 内の x';a()};
function d() {
var x = 'd 内の x、クロージャで作成された関数';
return function(){ echo(x)}};
a();// ホスト内の x
b ();// b 内の x
c();// ホスト内の x
d()( );// d の中に x があり、クロージャで作成した関数が最初の文で呼び出されます。「スタック」には次の内容があることがわかります (スタックの最上部は左側にあります):
[ARI a] → [ホスト] A の静的リンクはホストに直接接続されます。これは、x が a で定義されていないためです。インタプリタは x を探します。b を呼び出すと、静的チェーンに沿ってホスト内で x が見つかります。 x は b のローカル変数に記録され、最後のエコーは x inside b: 'x inside b';
c を呼び出すときの状況はさらに興味深いものになります。 :
動的チェーン: [a]→[c]→[ホスト]
静的チェーン: [c]→[ホスト] [a]→[ホスト]
x のアドレス指定は後で実行されるためa を呼び出しても、静的リンクは依然としてホストを直接指します。当然のことながら、x は依然として「ホスト内の x」です。
d の状況はさらに興味深いものです。d は戻り値として関数を作成し、すぐに呼び出されます。d の戻り値は d のライフサイクル内で作成されるため、d の戻り値は静的です。 link は d を指しているため、呼び出されると、d の x が出力されます: 'x inside d、クロージャが作成した関数'。
静的リンクを作成するタイミング
Yueying と amingoo は、「クロージャ」は関数の「呼び出し時参照」であると述べましたが、「プログラミング言語の原則」では単に ARI と呼ばれていますが、違いは「プログラム」であるということです。 「設計言語の原則」の ARI はスタックに保存され、関数のライフサイクルが終了すると ARI は破棄されますが、JS クロージャーの場合はそうではなく、クロージャが存在しない場合に限り破棄されます。それとそのメンバーを指すポイント (というより、どのコードもそれを見つけることができません)。関数 ARI は、関数の「服」に包まれただけのオブジェクトとして単純に考えることができます。
「プログラミング言語の原理」で説明されている静的チェーンは呼び出されたときに作成されますが、静的チェーン間の関係はコードのコンパイル時に決定されます。たとえば、次のコード:
PROCEDURE a;
PROCEDURE b;
END
END
では、b と c の静的リンクがポイントされます。に。 b が呼び出され、b の変数が b のローカル変数に含まれていない場合、コンパイラはコードを生成し、変数または RTE が見つかるまで静的チェーンに沿ってスタックを検索します。
ada などのコンパイル言語とは異なり、JS は完全にインタープリタ型の言語であり、関数を動的に作成できるため、「静的なチェーンの保守」という問題が生じます。幸いなことに、JS 関数は erl のシンボルと同様に直接変更できません。したがって、静的リンクは定義されるたびに更新するだけで済みます。定義方法が function(){} であるか eval 代入であるかに関係なく、静的チェーンは関数の作成後に固定されます。
大きな例に戻りましょう。インタプリタが「function big(){...}」を実行すると、メモリ内に関数インスタンスが作成され、それがホストに静的に接続されます。ただし、最後の行で呼び出された場合、インタプリタはメモリ内の領域を ARI として描画します。私たちは ARI[big] になるのもいいかもしれません。実行ポインタが 2 行目に移動します。
実行が 3 行目に達すると、インタプリタは「f1」のインスタンスを作成し、それを ARI[big] に保存し、静的リンクを ARI[big] に接続します。次の行。インタプリタは「f2」のインスタンスを作成し、静的チェーンを接続します。次に、5 行目で f2 が呼び出されて ARI[f1] が作成され、f2 が f1 を呼び出して ARI[f1] が作成されます。f1 が x を出力したい場合は、x をアドレス指定する必要があります。
単純な変数のアドレス指定
続けて、x をアドレス指定する必要がありますが、x は f1 のローカル変数に現れないため、インタプリタはスタックを検索して出力から x を見つける必要があります。インタプリタは「スタック」に沿って層ごとに検索を行っていませんが、現時点では「スタック」が次のとおりであるため、ジャンプがあります。 big | x = 1
|HOST|
インタープリターがスタックに沿ってレイヤーごとに実際に検索する場合、出力は 2 になります。これは、Js 変数アドレス指定の本質、つまり静的チェーンに沿った検索に触れます。
上記の問題を続けると、実行ポインターは f1 の静的チェーンに沿って検索し、big が x=1 であることが判明するため、1 が出力され、すべて問題ありません。
では、静的リンクがループを形成し、アドレス指定の「無限ループ」を引き起こすのでしょうか? remember 関数は相互にネストされているため、心配する必要はありません。言い換えれば、関数はルート ツリーを形成し、すべての静的チェーン ポインターは最終的にホストに集約される必要があるため、「ポインター ループ」を心配するのはばかげています。 (逆に、動的スコープ言語のアドレス指定は簡単に無限ループを引き起こす可能性があります。)
ここで、単純な変数のアドレス指定の方法を要約します。インタプリタは現在の関数のローカル変数で変数名を検索します。 not found, it follow 静的チェーンは、変数が見つかるまで、またはホストまでトレースバックし、それでも変数が見つからないまでトレースバックします。
ARI の概要
次に、ARI がローカル変数 (パラメーターを含む)、このポインター、動的チェーン、そして最も重要なことに、関数実行時の関数インスタンスのアドレスを記録することを見てみましょう。 ARI は次の構造を持つと想像できます:
ARI :: {
variables :: *variableTable, //変数テーブル
dynamicLink :: *ARI, //ダイナミックリンク
instance :: * funtioninst //関数インスタンス
}
変数にはすべてのローカル変数、パラメーター、およびこのポインターが含まれます。dynamicLink は呼び出される ARI を指し、instance は関数インスタンスを指します。関数インスタンスには、
functioninst:: {
source:: *jsOperations, //関数命令
staticLink:: *ARI, //静的リンク
....
}
関数が呼び出されると、次の「正式なコード」が実際に実行されます:
*ARI p;
p = new ARI();
p->dynamicLink = thread. currentARI;
p->instance = 呼び出された関数
p->variables.insert (パラメータリスト、この参照)
thread.transfer(p->instance->operations[0])
Did見えますか? ARI を作成し、パラメータとこれを変数テーブルにプッシュし、スレッド ポインタを関数インスタンスの最初の命令に転送します。
関数が作成されたときはどうなるでしょうか?関数命令を割り当てた後、以下も必要になります。
newFunction->staticLink = thread.currentARI
これで問題は明らかになりました。関数の定義時に、現在の ARI を直接指す静的リンクを作成しました。スレッドの。これで、単純な変数アドレス指定の問題のほぼすべてが説明できます。たとえば、次のコード:
function test(){
for(i=0;i(function(t){ //この匿名関数は暫定的に f setTimeout(function(){echo('' t)},1000) //ここでの匿名関数は g
})(i)
} }
test()
これ このコードの効果は、1秒遅れて0 1 2 3 4の順に出力することです。 setTimeout が動作する関数に注目してみましょう。静的リンクが作成されると、(ARI の) f の変数テーブルには i が含まれます (パラメータはローカル変数とみなされます)。 setTimeout の期限が切れると、匿名関数 g は変数 t を検索します。変数 t は、匿名関数 f の ARI 内で見つかります。したがって、0 1 2 3 4 が作成順に 1 つずつ出力されます。
パブリック匿名関数 f の関数インスタンスには合計 5 つの ARI があります (関数が呼び出されるたびに ARI が 1 回作成されることを覚えていますか?)。これに対応して、g も 5 回「作成」されます。最初の setTimeout が期限切れになる前に、スタックには次のレコードと同等のレコードが存在します (g を 5 に分けて書きました)。 t =0 ←——————g0
の静的リンク; t=1 ←——————fの静的リンク
| t=2 —— ————g2
| f の aRI ←—————— g3
| t=4 の aRI ←—————— g4 リンクの静的
------
g0 が呼び出されるとき、「スタック」は次のようになります:
テストの ARI [ループの最後に i=5]
| f の ARI; t=0 ←—————— f の ARI; t=1 ←—————— f の ARI; t=2 ←—— ————g2
の静的リンク; t=3 ←——————fの静的リンク
| ————g4 静的リンク
------
g0 の ARI
| ここでは t をアドレス指定する必要があるため、... t=0
------
g0 の ARI は可能です。これは f シリーズの ARI にはなく、ホストに直接配置されていると見なすことができますが、アドレス指定に関係する静的リンクは依然として各 f の ARI に突き付けられています。 setTimeout は順番に待機キューにプッシュされるため、最終的な出力は 0 1 2 3 4 の順になります。
関数が再定義されると、静的リンクは変更されますか?
次の質問を見てみましょう: 関数が定義されると、静的リンクが確立されます。その後、関数が再定義されると、別の静的リンクが確立されますか?まず例を見てみましょう:
var x = "x in host";
f = function(){echo(x)};
function big(); 🎜>var x = 'x in big';
f();
f()
}
big(); 🎜>出力:
x in host
x in host
x in big
この例は、big が実行されると、ホスト内の f が再定義され、その静的リンクが理解しやすいかもしれません。 "new" f は big を指しているため、最後の行は 'x in big' を出力します。
しかし、次の例はもっと興味深いものです:
var x = "x in host";
f();関数 big(){
var x = 'x ';
var f1 = f; ()
}
big()
出力:
x in host
x in host
x in host
x in host
は、再定義が実行されることを意味しません。静的リンクを変更しますか?ただし、ここでの 2 つの代入は単なる代入であり、f1 と f のポインターのみが変更されます (JS 関数が参照型であることを思い出してください)。f の実際のインスタンスでは、静的リンクは変更されていません。 。したがって、ホストでは 4 つの出力は実際には x になります。
構造体 (オブジェクト) 内でのコンポーネント (属性) のアドレス指定の問題
キリスト教 (java) とモルモン教 (csh) の人々がこの奇妙な名前を使用することを許してください。ただし、JS オブジェクトはハッシュに非常に似ています。表で、このアドレス指定の問題を考えてみましょう。
a.b コンパイル済み言語は、a を見つけてから、それを後方に一定距離オフセットして b を見つけるコードを生成します。ただし、JS は完全に動的言語であり、オブジェクトのメンバーは次のことができます。プロトタイプの問題により、JS オブジェクトのメンバーのアドレス指定が非常に興味深いものになります。
オブジェクトはハッシュ テーブルです
いくつかの特別なメソッド (およびプロトタイプ メンバー) を除いて、オブジェクトはハッシュ テーブルとほぼ同じです。メソッドとプロパティは「ハッシュ テーブル」の「ラティス」に格納できるためです。で。 Yue バージョンは、彼の「JS Return of the King」に HashTable クラスを実装しました。
オブジェクト自体のプロパティのアドレス指定
「独自の」プロパティは、hasOwnProperty が true であるプロパティを指します。実装の観点から見ると、これはオブジェクト自体の「ハッシュ テーブル」のメンバーです。例:
function Point(x,y){
this.x = x;
this.y = y;
var a = new Point(1,2);
echo("a.x:" a.x)
Point コンストラクターは、「Point」オブジェクト a を作成し、x 属性と y 属性を設定します。そのため、a のメンバー テーブルには次のようになります。 - --> 1
| y | ---> 2
a.x を検索する場合、インタープリターは最初に a を見つけ、次に a のメンバー テーブルで x を検索し、1 を取得します。
コンストラクターからオブジェクトにメソッドを設定することは、同じ型の 2 つのオブジェクトが異なるメソッドを持つことになるため、良い戦略ではありません。
function Point(x,y){
this.x = x;
this.y = y;
this.abs = function(){return Math.sqrt(this.x*this.x this.y*this.y)}
}
var a = 新しいポイント (1,2);
var b = 新しいポイント (1,2)
echo("a.abs == b.abs ? " (a.abs==b.abs)) ;
echo("a.abs === b.abs ? " (a.abs===b.abs));
4 行目ではオブジェクトの abs メンバー ( Method ) は毎回作成されるため、a.abs と b.abs は実際には 2 つのまったく異なる関数インスタンスを指します。したがって、等しいように見える 2 つのメソッドは、実際には等しくありません。
プロトタイプのアドレス指定の問題に持ち込む
プロトタイプは、(クラスではなく) オブジェクトを指す関数 (クラス) の属性です。 「プロトタイプ」の考え方は、「猫から虎を描く」ことにたとえられます。「虎」と「猫」の間には、相手を継承する関係はなく、「虎」と「猫」の間には関係があるだけです。 」。プロトタイプは類似性に焦点を当てており、コードは次のように記述できます:
Tiger.prototype = new Cat() 関数のプロトタイプは単なる空のオブジェクトにすることもできます:
SomeClass.prototype = {} しましょう。のアドレス指定に戻って、 を使用して特定の属性を取得し、それがプロトタイプ内の属性だった場合はどうなるでしょうか。現象は、それは確かに得られたが、どのようにして得られたのかということです。オブジェクト自体のプロパティがプロトタイプのプロパティと同じ名前である場合はどうなるでしょうか?幸いなことに、オブジェクト自体のプロパティが優先されます。
Defining methods in prototypes is a good design strategy. If we change the above example:
function Point(x,y){
this.x = x;
this.y = y;
}
Point.prototype.abs = function(){return Math.sqrt(this.x*this.x this.y*this,y)}
var a = new Point(1,2);
var b = new Point(1, 2);
echo("a.abs == b.abs ? " (a.abs==b.abs));
echo("a.abs === b.abs ? " (a .abs===b.abs));
Now, the outputs are finally equal. The reason is that a.abs and b.abs point to the member abs of the Point class prototype, so the outputs are equal. However, we cannot directly access Point.prototype.abs, and an error will occur during testing. Correction: After re-testing, the "Point.prototype.abs cannot be accessed" problem is a problem with the JSConsole I used. The reply is correct, thank you for your correction!
The prototype chain can be very long, or even wound into a loop. Consider the following code:
A = function(x){this.x = x};
B = function(x){this.y = x};
A.prototype = new B(1 );
B.prototype = new A(1);
var a = new A(2);
echo(a.x ' , ' a.y);
var b = new B(2) ;
echo(b.x ' , ' b.y);
The relationship described is probably "I am like you, and you are like me." The prototype pointer causes the following output:
2, 1
1, 2
When searching for a.y, "a.prototype" was found along the prototype chain, and the output was 1; the same principle applies to b.x . Now, we want to output the unregistered attribute "a.z":
echo(tyoeof a.z) We are surprised that there is no infinite loop here. It seems that the interpreter has a mechanism to deal with the problem of the prototype chain becoming a loop. At the same time, the prototype will either form a tree or a single ring, and will not have a multi-ring structure. This is a very simple graph theory.
This: Hidden rules in functions
The most troublesome hidden rule in method (function) calling is this problem. Logically speaking, this is a pointer pointing to the caller (an object). But if this always pointed to the caller, the world would be wonderful. But this damn pointer will "kick your dog" every now and then. Possible modifications include call, apply, asynchronous call and "window.eval".
I prefer to treat this as a parameter, just like self in lua. Lua's self can be passed explicitly or called with a colon:
a:f(x,y,z) === a.f(a,x,y,z) The same is true for "prime" method calls in JS This looks like:
a.f(x,y,z) === a.f.call(a,x,y,z)f.call is the truly "clean" calling form, just like the clean calling in Lua . Many people say that Lua is a clear version of JS. Lua simplifies many things of JS and exposes many hidden rules of JS. This is true.
The principle of correcting "this"
"Use closure to correct this" mentioned above in "The Return of the King", first look at the code:
button1.onclick = (
function(e){return function (){button_click.apply(e,arguments)}}
)(button1) Don’t underestimate this line of code. In fact, it creates an ARI, binds button1 here, and then returns a function. The function forces e calls button_click for the caller (subject), so this passed to button_click is e, which is button1! After the event binding is completed, the environment will probably look like the following:
button1.onclick = _F_; //Set a name for the returned anonymous function
_F_.staticLink = _ARI_; //Anonymous function called after creation ARI
_ARI_[e] = button1 //The e in the anonymous ARI parameter table is also the e that _F_ is looking for
So, when we click the button, _F_ will be called, and _F_ initiates One caller is the button_click function of e. According to our previous analysis, e is equal to button1, so we get a safe "specified caller" method. Maybe we can continue to develop this idea and make a universal interface:
bindFunction = function(f,e){ //We are good people, we don’t change the prototype, we don’t change...
return function(){
f.apply(e,arguments)
}
}

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++ ラムダ式におけるクロージャの意味は何ですか? C++ ラムダ式におけるクロージャの意味は何ですか? Apr 17, 2024 pm 06:15 PM

C++ では、クロージャは外部変数にアクセスできるラムダ式です。クロージャを作成するには、ラムダ式の外部変数をキャプチャします。クロージャには、再利用性、情報の隠蔽、評価の遅延などの利点があります。これらは、イベント ハンドラーなど、外部変数が破棄されてもクロージャが外部変数にアクセスできる現実の状況で役立ちます。

C++ 関数におけるクロージャの長所と短所は何ですか? C++ 関数におけるクロージャの長所と短所は何ですか? Apr 25, 2024 pm 01:33 PM

クロージャは、外部関数のスコープ内の変数にアクセスできる入れ子関数です。その利点には、データのカプセル化、状態の保持、および柔軟性が含まれます。デメリットとしては、メモリ消費量、パフォーマンスへの影響、デバッグの複雑さなどが挙げられます。さらに、クロージャは匿名関数を作成し、それをコールバックまたは引数として他の関数に渡すことができます。

C++ラムダ式でクロージャを実装するにはどうすればよいですか? C++ラムダ式でクロージャを実装するにはどうすればよいですか? Jun 01, 2024 pm 05:50 PM

C++ ラムダ式は、関数スコープ変数を保存し、関数からアクセスできるようにするクロージャーをサポートしています。構文は [キャプチャリスト](パラメータ)->戻り値の型{関数本体} です。 Capture-list は、キャプチャする変数を定義します。[=] を使用してすべてのローカル変数を値によってキャプチャするか、[&] を使用してすべてのローカル変数を参照によってキャプチャするか、[variable1, variable2,...] を使用して特定の変数をキャプチャできます。ラムダ式はキャプチャされた変数にのみアクセスできますが、元の値を変更することはできません。

クロージャによって引き起こされるメモリリークの問題を解決する クロージャによって引き起こされるメモリリークの問題を解決する Feb 18, 2024 pm 03:20 PM

タイトル: クロージャによって引き起こされるメモリ リークと解決策 はじめに: クロージャは JavaScript における非常に一般的な概念であり、内部関数が外部関数の変数にアクセスできるようにします。ただし、クロージャを誤って使用すると、メモリ リークが発生する可能性があります。この記事では、クロージャによって引き起こされるメモリ リークの問題を調査し、解決策と具体的なコード例を提供します。 1. クロージャによるメモリリーク クロージャの特徴は、内部関数が外部関数の変数にアクセスできることです。つまり、クロージャ内で参照される変数はガベージコレクションされません。不適切に使用すると、

関数ポインタとクロージャが Golang のパフォーマンスに与える影響 関数ポインタとクロージャが Golang のパフォーマンスに与える影響 Apr 15, 2024 am 10:36 AM

関数ポインタとクロージャが Go のパフォーマンスに与える影響は次のとおりです。 関数ポインタ: 直接呼び出しよりわずかに遅くなりますが、可読性と再利用性が向上します。クロージャ: 一般に遅いですが、データと動作をカプセル化します。実際のケース: 関数ポインターは並べ替えアルゴリズムを最適化でき、クロージャーはイベント ハンドラーを作成できますが、パフォーマンスの低下をもたらします。

Java ではクロージャはどのように実装されますか? Java ではクロージャはどのように実装されますか? May 03, 2024 pm 12:48 PM

Java のクロージャを使用すると、外部関数が終了した場合でも、内部関数が外部スコープの変数にアクセスできるようになります。匿名の内部クラスを通じて実装されると、内部クラスは外部クラスへの参照を保持し、外部変数をアクティブに保ちます。クロージャによりコードの柔軟性が向上しますが、匿名の内部クラスによる外部変数への参照により、それらの変数が存続するため、メモリ リークのリスクに注意する必要があります。

PHP 関数の連鎖呼び出しとクロージャ PHP 関数の連鎖呼び出しとクロージャ Apr 13, 2024 am 11:18 AM

はい、コードの単純さと読みやすさは、連鎖呼び出しとクロージャーによって最適化できます。連鎖呼び出しは、関数呼び出しを流暢なインターフェイスにリンクします。クロージャは再利用可能なコード ブロックを作成し、関数の外の変数にアクセスします。

golangの匿名関数とクロージャの長所と短所のまとめ golangの匿名関数とクロージャの長所と短所のまとめ May 05, 2024 am 09:54 AM

匿名関数は簡潔で匿名ですが、可読性が低く、デバッグが困難です。クロージャはデータをカプセル化して状態を管理できますが、メモリの消費と循環参照が発生する可能性があります。実際のケース: 匿名関数は単純な数値処理に使用でき、クロージャは状態管理を実装できます。

See all articles