ホームページ ウェブフロントエンド jsチュートリアル js クロージャをさらに理解することができます (詳細)

js クロージャをさらに理解することができます (詳細)

Oct 18, 2018 pm 01:39 PM
javascript

この記事の内容は、js クロージャを (詳細に) 理解するのに役立ちます。必要な方は参考にしていただければ幸いです。

翻訳者: クロージャについてはよく議論されているので、クロージャを理解していなくても、JS について知っていると言うのは恥ずかしいですが、この記事を読んだとき、私の目は輝きました。また、クロージャについても理解することができ、クラスとプロトタイプ チェーンについてもある程度の知識が得られました。これは 2012 年の記事で、少し早いものですが、内容は非常に明確です。読者に新たな理解をもたらすことができれば幸いです。

クロージャは、JavaScript 言語のやや複雑で誤解されている機能です。簡単に言えば、クロージャはメソッド (関数) と、メソッドが作成されたときの環境への参照を含むオブジェクトです。クロージャを完全に理解するには、js の 2 つの機能も理解する必要があります。1 つはファーストクラス関数、もう 1 つは内部関数です。

第一級関数

js では、メソッドは他のデータ型に簡単に変換できるため、第一級市民です。たとえば、第 1 レベルのメソッドをオンザフライで構築し、変数に割り当てることができます。他のメソッドに渡したり、他のメソッドを通じて返すこともできます。これらの基準を満たすことに加えて、メソッドには独自のプロパティとメソッドもあります。
次の例を通じて、第 1 レベルのメソッドの機能を見てみましょう。

var foo = function() {
  alert("Hello World!");
};

var bar = function(arg) {
  return arg;
};

bar(foo)();
ログイン後にコピー
翻訳者注: 原文のコードの説明は省略しますが、ここに反映されているのは、第 1 レベルのメソッドがパラメータを返すことができ、そのパラメータが別の第 1 レベルの関数である可能性があり、返された結果も同様であるということです。呼ばれる。

内部メソッド/内部関数

内部メソッドまたはネストされたメソッドは、外部メソッドが呼び出されるたびに、内部メソッドのインスタンスが作成されます。次の例は、内部メソッドの使用を反映しています。add メソッドは外部メソッドであり、doAdd は内部メソッドです。

function add(value1, value2) {
  function doAdd(operand1, operand2) {
    return operand1 + operand2;
  }

  return doAdd(value1, value2);
}

var foo = add(1, 2);
// foo equals 3
ログイン後にコピー

この例の重要な特徴は、内部メソッドが外部メソッドのスコープを取得することです。これは、内部メソッドが外部メソッドの変数、パラメーターなどを使用できることを意味します。この例では、add() のパラメーター value1 および value2 が doAdd() の operand1 および operand2 パラメーターに渡されます。ただし、doAdd は value1 と value2 を直接取得できるため、これは必須ではありません。したがって、上の例を次のように書くこともできます。

function add(value1, value2) {
  function doAdd() {
    return value1 + value2;
  }

  return doAdd();
}

var foo = add(1, 2);
// foo equals 3
ログイン後にコピー

クロージャの作成

内部メソッドは外部メソッドのスコープを取得し、クロージャを形成します。典型的なシナリオは、外部関数が内部メソッドを返し、外部環境への参照を保持し、スコープ内のすべての変数を保存するというものです。
次の例は、クロージャを作成して使用する方法を示しています。

function add(value1) {
  return function doAdd(value2) {
    return value1 + value2;
  };
}

var increment = add(1);
var foo = increment(2);
// foo equals 3
ログイン後にコピー

説明:

  • add は内部メソッド doAdd を返し、doAdd は add のパラメータを呼び出し、クロージャが作成されます。

  • value1 は add メソッドのローカル変数であり、doAdd の非ローカル変数です (非ローカル変数とは、変数が関数本体にも関数本体にも存在しないことを意味します)グローバル世界)、value2 は doAdd のローカル変数です。

  • add(1) が呼び出されると、クロージャが作成され、クロージャの参照環境に格納されます。value1 は 1 にバインドされ、バインドされた 1 は と等価です。この機能の「ブロッキング」が「クロージャ」の名前の由来でもあります。

  • increment(2) が呼び出されると、クロージャ関数に入ります。つまり、value1 が 1 である doAdd が呼び出されるため、クロージャは本質的に次の関数とみなすことができます。

  • ##
function increment(value2) {
  return 1 + value2;
}
ログイン後にコピー

#クロージャを使用するのはどのような場合ですか?

クロージャは多くの機能を実現できます。たとえば、コールバック関数を指定されたパラメータにバインドします。あなたの生活と成長を容易にする 2 つのシナリオについて話しましょう。

  1. タイマーとの連携

クロージャは、setTimeout および setInterval と組み合わせると非常に便利です。クロージャを使用すると、指定したパラメータをコールバック関数に渡すことができます。たとえば、指定された dom に 1 秒ごとに文字列を挿入します。

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Closures</title>
  <meta charset="UTF-8" />
  <script>
    window.addEventListener("load", function() {
      window.setInterval(showMessage, 1000, "some message<br />");
    });

    function showMessage(message) {
      document.getElementById("message").innerHTML += message;
    }
  </script>
</head>
<body>
  <span id="message"></span>
</body>
</html>
ログイン後にコピー
残念ながら、IE は setInterval コールバックへのパラメータの受け渡しをサポートしていません。IE のページには「何らかのメッセージ」が表示されませんが、「未定義」が表示されます (この問題を解決するには、値が showMessage() に渡されません)。 , 期待値は、クロージャを通じてコールバック関数にバインドできます。上記のコードを書き換えることができます:

window.addEventListener("load", function() {
  var showMessage = getClosure("some message<br />");

  window.setInterval(showMessage, 1000);
});

function getClosure(message) {
  function showMessage() {
    document.getElementById("message").innerHTML += message;
  }

  return showMessage;
}
ログイン後にコピー
2. プライベート プロパティをシミュレートする

ほとんどのオブジェクト指向プログラミング言語は、オブジェクトのプライベート プロパティをサポートしています。ただし、js は純粋なオブジェクト指向言語ではないため、プライベート プロパティの概念はありません。ただし、クロージャを通じてプライベート プロパティをシミュレートできます。クロージャには、クロージャが作成された環境への参照が含まれていることに注意してください。この参照は現在のスコープには含まれていないため、この参照は本質的にはプライベート プロパティです。
次の例を見てください (翻訳者: コードのテキスト説明は省略します):

function Person(name) {
  this._name = name;

  this.getName = function() {
    return this._name;
  };
}
ログイン後にコピー
ここには重大な問題があります。js はプライベート属性をサポートしていないため、他の人が名前を変更することを防ぐことができません。たとえば、Colin という名前の Person インスタンスを作成し、名前を Tom に変更します。

var person = new Person("Colin");

person._name = "Tom";
// person.getName() now returns "Tom"
ログイン後にコピー

没有人愿意不经同意就被别人改名字,为了阻止这种情况的发生,通过闭包让_name字段变成私有。看如下代码,注意这里的_name是Person构造器的本地变量,而不是对象的属性,闭包形成了,因为外层方法Person对外暴露了一个内部方法getName。

function Person(name) {
  var _name = name;// 注:区别在这里

  this.getName = function() {
    return _name;
  };
}
ログイン後にコピー

现在,当getName被调用,能够保证返回的是最初传入类构造器的值。我们依然可以为对象添加新的_name属性,但这并不影响闭包getName最初绑定的值,下面的代码证明,_name字段,事实私有。

var person = new Person("Colin");

person._name = "Tom";
// person._name is "Tom" but person.getName() returns "Colin"
ログイン後にコピー

什么时候不要用闭包?

正确理解闭包如何工作何时使用非常重要,而理解什么时候不应该用它也同样重要。过度使用闭包会导致脚本执行变慢并消耗额外内存。由于闭包太容易创建了,所以很容易发生你都不知道怎么回事,就已经创建了闭包的情况。本节我们说几种场景要注意避免闭包的产生。
1.循环中
循环中创建出闭包会导致结果异常。下例中,页面上有三个按钮,分别点击弹出不同的话术。然而实际运行,所有的按钮都弹出button4的话术,这是因为,当按钮被点击时,循环已经执行完毕,而循环中的变量i也已经变成了最终值4.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Closures</title>
  <meta charset="UTF-8" />
  <script>
    window.addEventListener("load", function() {
      for (var i = 1; i < 4; i++) {
        var button = document.getElementById("button" + i);

        button.addEventListener("click", function() {
          alert("Clicked button " + i);
        });
      }
    });
  </script>
</head>
<body>
  <input type="button" id="button1" value="One" />
  <input type="button" id="button2" value="Two" />
  <input type="button" id="button3" value="Three" />
</body>
</html>
ログイン後にコピー

去解决这个问题,必须在循环中去掉闭包(译者:这里的闭包指的是click事件回调函数绑定了外层引用i),我们可以通过调用一个引用新环境的函数来解决。下面的代码中,循环中的变量传递给getHandler函数,getHandler返回一个闭包(译者:这个闭包指的是getHandler返回的内部方法绑定传入的i参数),独立于原来的for循环。

function getHandler(i) {
  return function handler() {
    alert("Clicked button " + i);
  };
}

window.addEventListener("load", function() {
  for (var i = 1; i < 4; i++) {
    var button = document.getElementById("button" + i);

    button.addEventListener("click", getHandler(i));
  }
});
ログイン後にコピー

2.构造函数里的非必要使用
类的构造函数里,也是经常会产生闭包的错误使用。我们已经知道如何通过闭包设置类的私有属性,而如果当一个方法不需要调用私有属性,则造成的闭包是浪费的。下面的例子中,Person类增加了sayHello方法,但是它没有使用私有属性。

function Person(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };

  this.sayHello = function() {
    alert("Hello!");
  };
}
ログイン後にコピー

每当Person被实例化,创建sayHello都要消耗时间,想象一下有大量的Person被实例化。更好的实践是将sayHello放入Person的原型链里(prototype),原型链里的方法,会被所有的实例化对象共享,因此节省了为每个实例化对象去创建一个闭包(译者:指sayHello),所以我们有必要做如下修改:

function Person(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };
}

Person.prototype.sayHello = function() {
  alert("Hello!");
};
ログイン後にコピー

需要记得一些事情

闭包包含了一个方法,以及创建它的代码环境引用

闭包会在外部函数包含内部函数的情况下形成

闭包可以轻松的帮助回调函数传入参数

类的私有属性可以通过闭包模拟

类的构造器中使用闭包不是一个好主意,将它们放到原型链中

以上が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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の 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 チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

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

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

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

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

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

See all articles