ホームページ ウェブフロントエンド jsチュートリアル 経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。

経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。

Nov 25, 2019 pm 05:00 PM
js ピット 閉鎖

経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。

#古いドライバーは、JS クロージャのさまざまな落とし穴を徹底的に理解するのに役立ちます

クロージャは JS です一般的な開発手法、クロージャとは何ですか?
#クロージャは、別の関数のスコープ内の変数にアクセスできる関数を指します。明確に言うと、クロージャは他の関数のスコープ内の変数にアクセスできる関数です。例:

function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
ログイン後にコピー

多くの人は、匿名関数とクロージャの関係を理解できないでしょう。実際、クロージャはスコープの観点から定義されます。これは、inner が外側のスコープ内の変数にアクセスするため、inner はクロージャ関数です。定義は非常にシンプルですが、このポインタや変数のスコープなど落とし穴が多く、ちょっとした不注意でメモリリークを引き起こす可能性があります。問題を横に置いて、次の質問について考えてみましょう。クロージャー関数が他の関数のスコープにアクセスできるのはなぜですか?

スタックの観点から js 関数を見る

基本変数 の値は通常スタック メモリに格納されますが、オブジェクト型変数の値はヒープ メモリに格納され、スタック メモリには対応する空間アドレスが格納されます。基本データ型: 数値、ブール値、未定義、文字列、Null。

var  a = 1   //a是一个基本类型
var  b = {m: 20 }   //b是一个对象
ログイン後にコピー

対応するメモリ ストレージ:

経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。b={m:30} を実行すると、ヒープ内に新しいオブジェクト {m:30} が存在します。メモリ 、スタック メモリ内の b は新しい空間アドレス ({m: 30} を指す) を指し、ヒープ メモリ内の元の {m: 20} はプログラム エンジンによってガベージ コレクションされ、メモリ領域が節約されます。 js 関数もオブジェクトであり、ヒープ メモリとスタック メモリにも格納されることがわかっています。変換を見てみましょう:

var a = 1;
function fn(){
    var b = 2;
    function fn1(){
        console.log(b);
    }
    fn1();
}
fn();
ログイン後にコピー

経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。**

##スタックは先入れ後出しのデータ構造です:

1 fn を実行する前は、グローバル実行環境 (ブラウザーがウィンドウ スコープ) にあり、変数 a が存在します。グローバル スコープ;

2 「fn」と入力します。このとき、スタック メモリは fn の実行環境をプッシュします。この環境には変数 b と関数オブジェクト fn1 が含まれます。ここで、独自の実行で定義された変数にアクセスできます。環境とグローバル実行環境

3 fn1 と入力します。この時点で、スタック メモリは fn1 の実行環境をプッシュします。そこには他の変数は定義されていませんが、fn の変数とその実行環境にアクセスできます。プログラムが変数にアクセスすると、変数は一番下のスタックに移動するため、グローバル実行環境に対応する変数がないことが判明すると、プログラムはアンダーファイン エラーをスローします。

4 fn1() が実行されると、fn1 の実行環境が cup によって破壊され、その後 fn() が実行されると、fn の実行環境も破壊され、グローバル実行環境だけが残ります。現在、b 変数と fn1 関数オブジェクトはなく、a と fn (関数宣言の範囲はウィンドウの下にあります) のみです。

**

関数内の変数へのアクセスは、関数スコープ チェーン 変数が存在するかどうか。関数スコープ チェーンは、関数が配置されている実行環境スタックに従ってプログラムによって初期化されるため、上記の例では、変数 b を fn1 に出力し、対応する fn 実行環境を見つけます。 fn1 変数のスコープチェーンに応じて b.したがって、プログラムが関数を呼び出すと、次の作業が行われます。実行環境、初期関数スコープ チェーン、および引数パラメーター オブジェクトを準備します

元の例のアウターとインナー

function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
var  inner = outer()   // 获得inner闭包函数
inner()   //"变量1"
ログイン後にコピー

プログラムが var inner = inner() の実行を終了しても、実際には、その内部の変数 a はまだ inner の関数スコープ チェーンによって参照されているため、outer の実行環境は破壊されません。 、これは、内部と外部の実行環境が破棄され、調整される場合にのみ、書籍「JavaScript Advanced Programming」では次のように推奨されています: クロージャは、クロージャを含む関数のスコープを保持するため、他の関数よりも多くのコンテンツを占有するため、過度の使用は避けてください。クロージャの数が多いと、過剰なメモリ使用量が発生します。

これで、クロージャ、対応するスコープとスコープ チェーンが理解できました。トピックに戻ります。

落とし穴 1: 参照される変数は変更される可能性があります

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function () {
            console.info(i)
        }
     }
     return result
}
ログイン後にコピー
結果内の各クロージャー関数は、対応する数値 1、2、3、4、...、10 を出力するように見えますが、各クロージャー関数は外部の実行環境で変数 i にアクセスするため、これは実際には当てはまりません。 i、ループが終了すると i は 10 になったので、各クロージャ関数が実行され、結果は 10, 10, ..., 10

この問題を解決するにはどうすればよいですか?

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function (num) {
             return function() {
                   console.info(num);    // 此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样
             }
        }(i)
     }
     return result
}
ログイン後にコピー

落とし穴 2: これは問題を示しています

var object = {
     name: &#39;&#39;object",
     getName: function() {
        return function() {
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向window
ログイン後にコピー
落とし穴 3: メモリ リークの問題

function  showId() {
    var el = document.getElementById("app")
    el.onclick = function(){
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
}
// 改成下面
function  showId() {
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
    el = null    // 主动释放el
}
ログイン後にコピー
ヒント 1: クロージャを使用して再帰呼び出しの問題を解決する

function  factorial(num) {
   if(num<= 1) {
       return 1;
   } else {
      return num * factorial(num-1)
   }
}
var anotherFactorial = factorial
factorial = null
anotherFactorial(4)   // 报错 ,因为最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现
// 使用闭包实现递归
function newFactorial = (function f(num){
    if(num<1) {return 1}
    else {
       return num* f(num-1)
    }
}) //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial
ログイン後にコピー
** ヒント 2: クロージャを使用してブロックレベルのスコープを模倣する**

es6以前は、var を使用して変数を定義するときに変数の昇格の問題がありました。例:

for(var i=0; i<10; i++){
    console.info(i)
}
alert(i)  // 变量提升,弹出10

//为了避免i的提升可以这样做
(function () {
    for(var i=0; i<10; i++){
         console.info(i)
    }
})()
alert(i)   // underfined   因为i随着闭包函数的退出,执行环境销毁,变量回收
ログイン後にコピー
もちろん、現在はほとんどの変数は es6 の let と const を使用して定義されています。

この記事はここで終了しました。さらに興味深いコンテンツについては、PHP 中国語 Web サイトの
JavaScript ビデオ チュートリアル

列に注目してください。

以上が経験豊富なドライバーが、JS クロージャーのさまざまな落とし穴を徹底的に理解するのに役立ちます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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)

推奨: 優れた JS オープンソースの顔検出および認識プロジェクト 推奨: 優れた JS オープンソースの顔検出および認識プロジェクト Apr 03, 2024 am 11:55 AM

顔の検出および認識テクノロジーは、すでに比較的成熟しており、広く使用されているテクノロジーです。現在、最も広く使用されているインターネット アプリケーション言語は JS ですが、Web フロントエンドでの顔検出と認識の実装には、バックエンドの顔認識と比較して利点と欠点があります。利点としては、ネットワーク インタラクションの削減とリアルタイム認識により、ユーザーの待ち時間が大幅に短縮され、ユーザー エクスペリエンスが向上することが挙げられます。欠点としては、モデル サイズによって制限されるため、精度も制限されることが挙げられます。 js を使用して Web 上に顔検出を実装するにはどうすればよいですか? Web 上で顔認識を実装するには、JavaScript、HTML、CSS、WebRTC など、関連するプログラミング言語とテクノロジに精通している必要があります。同時に、関連するコンピューター ビジョンと人工知能テクノロジーを習得する必要もあります。 Web 側の設計により、次の点に注意してください。

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

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

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

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

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

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

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

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

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

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

jsとvueの関係 jsとvueの関係 Mar 11, 2024 pm 05:21 PM

js と vue の関係: 1. Web 開発の基礎としての JS、2. フロントエンド フレームワークとしての Vue.js の台頭、3. JS と Vue の補完関係、4. JS と Vue の実用化ビュー。

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

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

See all articles