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

この記事の内容は、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 秒ごとに文字列を挿入します。

nbsp;html>


  <title>Closures</title>
  <meta>
  <script>
    window.addEventListener("load", function() {
      window.setInterval(showMessage, 1000, "some message<br />");
    });

    function showMessage(message) {
      document.getElementById("message").innerHTML += message;
    }
  </script>


  <span></span>

残念ながら、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.

nbsp;html>


  <title>Closures</title>
  <meta>
  <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>


  <input>
  <input>
  <input>

去解决这个问题,必须在循环中去掉闭包(译者:这里的闭包指的是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 <p>2.构造函数里的非必要使用<br>类的构造函数里,也是经常会产生闭包的错误使用。我们已经知道如何通过闭包设置类的私有属性,而如果当一个方法不需要调用私有属性,则造成的闭包是浪费的。下面的例子中,Person类增加了sayHello方法,但是它没有使用私有属性。</p><pre class="brush:php;toolbar:false">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 までご連絡ください。
PythonとJavaScriptの未来:傾向と予測PythonとJavaScriptの未来:傾向と予測Apr 27, 2025 am 12:21 AM

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

Python vs. JavaScript:開発環境とツールPython vs. JavaScript:開発環境とツールApr 26, 2025 am 12:09 AM

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

JavaScriptはCで書かれていますか?証拠を調べるJavaScriptはCで書かれていますか?証拠を調べるApr 25, 2025 am 12:15 AM

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptの役割:WebをインタラクティブでダイナミックにするJavaScriptの役割:WebをインタラクティブでダイナミックにするApr 24, 2025 am 12:12 AM

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

CおよびJavaScript:接続が説明しましたCおよびJavaScript:接続が説明しましたApr 23, 2025 am 12:07 AM

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

See all articles

ホット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 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

メモ帳++7.3.1

メモ帳++7.3.1

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

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

SublimeText3 中国語版

SublimeText3 中国語版

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

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません