一緒にクロージャについて知りましょう
#関連する学習に関する推奨事項:まえがき
# 終わりに は、フロントエンド開発者にとって常に回避できないハードルであり、好むと好まざるにかかわらず、仕事や面接で遭遇することがあります。クロージャについての理解は人それぞれ異なりますので、ここでは私自身のクロージャについての理解をお話します。 (理解に矛盾がある場合は、ご自身でご参照ください)
クロージャの定義方法定義を与える前に、他の人がどのようにクロージャを定義しているかを見てみるとよいでしょう:関数オブジェクトはスコープ チェーンを通じて相互に関連付けることができ、関数本体内の変数は関数スコープに保存できます。この機能は、コンピュータ サイエンスの文献では「クロージャ」と呼ばれています - JavaScript オーソリティ ガイド (第 6 版)
#クロージャは、別の関数のスコープ内の変数にアクセスできる関数です。クロージャを作成する一般的な方法は、別の関数の中に関数を作成することです。 --Advanced Programming in JavaScript (Third Edition)
関数が現在の字句スコープ内にある場合でも、関数がその字句スコープを記憶してアクセスできる場合、クロージャが発生します。ドメインの外。 -- あなたの知らない JavaScript (第 1 巻)上記の段落の説明は同じではありませんが、注意深く味わってみると、いくつかの共通点を見つけることができます。これらの中で最も重要なのは、異なるスコープ間の
接続 です。もちろん、上記の定義を直接引用することもできます (結局のところ、上記の定義は比較的信頼できるものです)。ここでは、著者は最後の段落の定義を好み、書籍「あなたが知らない JavaScript (第 1 巻)」を強く推奨します。 、注意深く繰り返し読む価値があります。
クロージャにどのようなナレッジ ポイントが関係しているか定義を与えるだけでは十分ではなく、どのようなナレッジ ポイントが内部的に関係しているのかも調査する必要があります。筆者が役立つと思った知識を以下に挙げます。 スコープとスコープ チェーン実は、著者は皆さんがこれについて考えたことがあることを知っています (いいえ、これを考えたことがない人は誰もいません)。これで誰もがscope を知ることができました。ここではそれを簡単に説明し、そのプロセスを見ていきます。
スコープ: 変数を名前で検索するための一連のルール。グローバルスコープ、関数スコープ、ブロックスコープの3種類に分かれます。注目すべきはES6の新しい仕様であるブロックスコープです。中括弧
{} 内の
let および const を使用して定義された変数はスコープにバインドされ、中括弧の外側からはアクセスできません。
注: 中括弧の先頭と let 変数宣言の前の間に 一時的なデッド ゾーンがあります (この点はこの記事の範囲外です) 。 スコープ チェーン: 異なるスコープが一緒にトラップされると、スコープ チェーンが形成されます。検索方向は内側から外側であることに注意してください。
スコープの検索方向が内側から外側になるのはなぜですか?これは興味深い質問です。個人的には、js の実行関数がスタックにプッシュされる方法によって決まると思います (少し話が逸れたように感じます。興味のある友人は情報を確認してください)。 字句スコープ
関数が別の関数スコープ内の変数にアクセスできる (または現在のスコープを覚えていて、現在のスコープの外にアクセスできる) 理由の重要なポイント
は字句スコープ### 仕事で。これは非常に重要ですが、誰もがこの知識ポイントを知っているわけではないので、ここで簡単に説明しましょう。
プログラミングの世界には、スコープの 2 つの作業モードがあります。1 つは、ほとんどのプログラミング言語で使用される
字句スコープ で、もう 1 つはその逆です。
ダイナミック スコープ
それ以外の場合は、例を挙げてみましょう:
字句スコープ: 変数とブロックのスコープはコードを書くときに決定され、オブジェクトや呼び出される場所によって変更されません (これは反対)。
let a = 1; function fn(){ let a = 2; function fn2(){ console.log(a); } return fn2; } let fn3 = fn(); fn3();
上記の定義から、fn3 ## であることがわかります。fn
はクロージャ関数
#fn2
のポインタ アドレスを取得しました。fn3 が実行されると、実際には
fn2 が実行され、内部の
a 変数は、スコープ チェーンの検索ルールでは、検出されるのは
fn スコープ内の変数
a であるため、最終出力は 1 ではなく 2 になります。 (下の図をご覧ください)
話は逸れますが、字句スコープを欺くにはどうすればよいでしょうか?

第一种方法是使用eval. eval可以把字符串解析成一个脚本来运行,由于在词法分析阶段,无法预测eval运行的脚本,所以不会对其进行优化分析。
第二种方法是with. with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with本身比较难掌握,使用不当容易出现意外情况(如下例子),不推荐使用 -.-
function Fn(obj){ with(obj){ a = 2; } } var o1 = { a:1 } var o2 = { b:1 } Fn(o1); console.log(o1.a); //2 Fn(o2); console.log(o2.a); //undefined; console.log(a); //2 a被泄漏到全局里面去了 // 这是with的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个
闭包能干啥?
闭包的使用场景可多了,平时使用的插件或者框架,基本上都有闭包的身影,可能您没留意过罢了。下面笔者列举一些比较常见的场景。
模拟私有变量和方法,进一步来说可以是模拟
模块化
;目前常用的AMD,CommonJS等模块规范,都是利用闭包的思想;柯里化函数或者偏函数;利用闭包可以把参数分成多次传参。如下面代码:
// 柯里化函数 function currying(fn){ var allArgs = []; function bindCurry(){ var args = [].slice.call(arguments); allArgs = allArgs.concat(args); return bindCurry; } bindCurry.toString = function(){ return fn.apply(null, allArgs); }; return bindCurry; }
实现防抖或者节流函数;
实现缓存结果(记忆化)的辅助函数:
// 该方法适合缓存结果不易改变的函数 const memorize = fn => { let memorized = false; let result = undefined; return (...args) => { if (memorized) { return result; } else { result = fn.apply(null,args); memorized = true; fn = undefined; return result; } }; };
如何区分闭包?
说了那么多,我怎么知道自己写的代码是不是闭包呢?先不说新手,有些代码的确隐藏的深,老鸟不仔细看也可能发现不了。 那有没有方法可以帮助我们区分一个函数是不是闭包呢?答案是肯定的,要学会善于利用周边的工具资源,比如浏览器。
打开常用的浏览器(chrome或者其他),在要验证的代码中打上debugger断点,然后看控制台,在scope里面的Closure(闭包)里面是否有该函数(如下图)。

闭包真的会导致内存泄漏?
答案是有可能。内存泄漏的原因在于垃圾回收(GC)无法释放变量的内存,导致运行一段时候后,可用内存越来越少,最终出现内存泄漏的情况。常见的内存泄漏场景有4种:全局变量;闭包引用;DOM事件绑定;不合理使用缓存。其中,闭包导致内存泄漏都是比较隐蔽的,用肉眼查看代码判断是比较难,我们可用借助chrome浏览器的Memory标签栏工具来调试。由于篇幅问题,不展开说明了,有兴趣自己去了解一下如何使用。
想了解更多编程学习,敬请关注php培训栏目!
以上が一緒にクロージャについて知りましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









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

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

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

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

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

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

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

クロージャでのメモリリークを防ぐにはどうすればよいでしょうか?クロージャは JavaScript の最も強力な機能の 1 つであり、関数のネストとデータのカプセル化を可能にします。ただし、クロージャでは、特に非同期やタイマーを扱う場合にメモリ リークが発生する傾向があります。この記事では、クロージャでのメモリ リークを防ぐ方法を説明し、具体的なコード例を示します。メモリ リークは通常、オブジェクトが不要になったにもかかわらず、そのオブジェクトが占有しているメモリを何らかの理由で解放できない場合に発生します。クロージャ内で、関数が外部変数を参照する場合、これらの変数は
