ホームページ ウェブフロントエンド jsチュートリアル JavaScriptのクロージャ内のクロージャ

JavaScriptのクロージャ内のクロージャ

Jun 16, 2020 am 09:30 AM
javascript

前面に書かれています


JavaScript ほとんど神話 JavaScript の使用経験はあるものの、クロージャの概念を実際には理解したことがない人にとって、クロージャを理解することは、ある種の生まれ変わりとなります。クロージャは、使用するために新しい構文を学習する必要があるツールではありません。クロージャは、字句スコープに基づいてコードを作成した場合の自然な結果です。言い換えれば、クロージャのためにクロージャを作成する必要はなく、作成するコードのどこにでもクロージャが存在します。 クロージャを本当に理解すると、ああ~、前に入力したコードにはたくさんのクロージャがあったことがわかります。

小さなデモ


次の例を注意深く見てみると、奇妙に感じるでしょう。これらはすべて result() を呼び出しているのに、なぜ結果が違う?

let count=500 //全局作用域
function foo1() {
  let count = 0;//函数全局作用域
  function foo2() {
    count++;//函数内部作用域
    console.log(count);
    return count;
  }
  return foo2;//返回函数
}
let result = foo1();
result();//结果为1
result();//结果为2
ログイン後にコピー

まず第一に、foo1() は foo2() 関数を返します。result() を呼び出すと、foo2() によって実行された関数が返されます。foo2() には何が含まれていますか? まず次のようになります。以下のように count 変数がありますが定義されていません JavaScript のスコープチェーンの定義により、関数内の変数が定義されていない場合はバブリング方式で上位を検索します次のレベルには続行しません。最上位ウィンドウまで 1 レベルを検索します。何もない場合は、未定義のエラーが報告されます。ここでは、foo1() で count を見つけるので、count 1、最初の出力は 1、そこにあります問題ありません。

 function foo2() {
    count++;
    console.log(count);
    return count;
  }
ログイン後にコピー

しかし、2 回目に result() を実行したときに問題が発生しました。なぜ 2 なのでしょうか? 処理によると、まず foo2() 関数内の count を探します。カウントがない場合は、外側の層でそれを探します。カウント = 0 が見つかった場合、カウント 1 は 1 である必要があります。これには、クロージャーの問題が含まれます。

JavaScriptのクロージャ内のクロージャ

最初デバッガを追加し、Google Chrome を右クリックしてリソースをクリックすると、右側にクロージャが表示されます。ブラウザの視覚化により、これが実際にクロージャであることが確認されました。そして、count=1 がクロージャに保存されています。これは、count を意味します=1 は破棄されておらず、次回 result() が呼び出されるときに count=2 になります。

スコープの理解


Clussure を学ぶには、これを理解する必要があります。 JavaScript のスコープ関連の知識:

1. グローバル スコープ
2. 関数スコープ
4. ブロックレベル スコープ (es6 の新機能、var 問題を解決し、 let 、 const を追加)

  var count = 100; //全局作用域
  function foo1() {
    var count = 0; //函数全局作用域
    return count; //返回函数
  }
  if (count == 1) {
    //块级作用域
    console.log(count);
  }
ログイン後にコピー

上記のコードは、スコープの分類を簡単に示しています。関数 (関数) もブロックレベルのスコープであることに注意してください。簡単に言うと、一般に {} をブロックとみなすことができます。レベル スコープ.

スコープ チェーン


スコープはスコープ内でネストされ、スコープ チェーンを形成します。外部スコープは内部スコープ スコープにアクセスできません。次の例を参照してください

function foo(){
var n=1
function foo2(){
  var m=1
  console.log(n) //1
}
foo2()
}
foo()
console.log(n) //err: n is not defined
ログイン後にコピー

上記のコードでは、内部 n にはグローバルにアクセスできませんが、ネストされた内部 foo2() は外部関数にアクセスできます。これは、スコープによって生成される特別な効果です。

さて、スコープ チェーンについては理解しました。例を見てみましょう (非常にわかりにくいので、注意して見てください):

 var name = 'Mike'; //第一次定义name
  function showName() {
    console.log(name);  //输出 Mike 还是 Jay ?     
  }

  function changeName() {
    var name = 'Jay'; //重新定义name
    showName(); //调用showName()
  }
  changeName();
ログイン後にコピー

上記の例の出力は何だと思いますか? 答えはマイクです。ここで新しい概念を紹介します。字句スコープには 2 つのモデルがあります:

  • 字句スコープ (静的): js 検索は、呼び出し時の位置ではなく、コードが記述されたときの位置に従って決定されます

  • 動的スコープ: Perl と Bash が現在使用されています (これについては自分で学習できます)

JavaScriptのクロージャ内のクロージャ

私たち字句スコープのルールを通じて再度分析できます。

  1. changeName() を呼び出すときは、この関数を見つけます

  2. var name = "Jay" を定義します

  3. showName()を呼び出します

  4. changeName()にshowName()があるか確認します。このメソッドは見つからなかったので、外側のメソッドを検索しました。レイヤーを検索し、

  5. を見つけました。console.log(name) を呼び出し、関数内を検索して名前があるかどうかを確認します。名前がない場合は、外側に検索して見つけました。name="Mike 「

  6. アウトプットマイク

クロージャ


理解しました 上記の知識を経て、私はついにクロージャに到達しました

クロージャの公式説明は 2 冊の本で説明されています:

##1. 小さな「黄色の」本 (JavaScript を知らない人): クロージャは次の場合に生成されます。関数は、現在の字句スコープ外で実行された場合でも、その関数が含まれている字句スコープを記憶してアクセスできます。

2. Little Red Book (JavaScript Advanced Programming) : クロージャとは、別の字句スコープにアクセスできることを意味します。 関数スコープ内の変数の関数

は非常に抽象的な概念です。私自身の理解の 1 つは次のとおりです。

変数 (上記の名前など) が関数に対してローカルではない場合、変数は関数のパラメータではありません。スコープと比較すると、これは自由変数 (外部変数を参照) であり、クロージャを形成します。
何と言うか? 最初に使用するものを見てみましょうデモ###

let count = 500; //全局作用域
function foo1() {
  let count = 0; //函数全局作用域
  function foo2() {
    let count2 = 1; //随便新增一个变量
    // count++;  注释
    debugger;
    //console.log(count); 注释
    //return count;  注释
  }
  return foo2; //返回函数
}
let result = foo1();
result(); //结果为1
result(); //结果为2
ログイン後にコピー

再次使用浏览器看看,这时我们就发现Closure已经消失了,这也就证实我说的,如果函数内部不调用外部的变量,就不会形成闭包.但是如果调用了外部变量,那么就会形成闭包. 这也就是说不是所有的函数嵌套函数都能形成闭包

<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/image/731/425/784/1592270826700856.jpg" class="lazy" title="1592270826700856.jpg" alt="JavaScriptのクロージャ内のクロージャ"/>

最后我们再来看一个循环闭包的例子

for (var i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    debugger;
    console.log(i); // 输出什么?   
  }, 1000);
}
ログイン後にコピー

答案 6 6 6 6 6 .因为setTimeout里面的回调函数是一个异步的过程(异步代表可以不用等待我这个代码先执行完,可以先往后执行),而for循环是同步的(代码只能从上往下的执行),立即执行,异步的setTimeout必须等待一秒才能执行,这时i早已经循环结束了.
解决办法有三个:

  1. 将for循环中的var 改成let

for (let i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    debugger;
    console.log(i); // 1 2 3 4 5 
  }, 1000);
}
ログイン後にコピー

这样就没有问题了, 因为let是有块级的功能,每一层循环都是独立的,互不影响,所以才能正常输出.
2. 把setTimeout()套上一个function

for (var i = 1; i <= 5; i++) {
  log(i); // 1 2 3 4 5
}
function log(i) {
  setTimeout(function timer() {
    debugger;
    console.log(i);
  }, 1000);
}
ログイン後にコピー

这样同样能够实现这个功能,原理和第一个方法一样,每一个log()都是独立的,互不影响,这样才能有正确的结果,var就是因为没有块级的功能,才会出问题 3. 包装成匿名函数

for (var i = 1; i <= 5; i++) {
  (function (i) {
    setTimeout(function timer() {
      debugger;
      console.log(i);
    }, 1000);
  })(i)
}
ログイン後にコピー

前面一个(func..)定义函数,后面一个(i)调用,这再JavaScript叫做立即执行函数,其实与第二种方式是一样的,只是写法不一样.

结语


理解JavaScript闭包是一项重要的技能,在面试中也常常会有,这是迈进高级JavaScript工程师的必经之路.

推荐教程: 《js教程

以上がJavaScriptのクロージャ内のクロージャの詳細内容です。詳細については、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)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

See all articles