検索
ホームページウェブフロントエンドjsチュートリアルJavascript の入れ子関数と Closures_JavaScript スキルに関する簡単な説明

【入れ子関数】
JavaScript では関数の埋め込みが可能であり、関数をデータとして使用することができ、関数の字句スコープの下で、従来のオブジェクト指向言語と驚くべき違いを生み出すことができます。
まず第一に、JavaScript 関数は動的ではなく字句的にスコープ設定されているため、関数は実行されるスコープではなく、定義されているスコープ内で実行されるため、ネストされた場合は簡単に理解できます。関数とその周囲の関数は同じ字句範囲内で定義されます。たとえば、次のような非常に当たり障りのないコード:
コード をコピーします。 コードは次のとおりです:

var x = 'グローバル';
関数 f () {
var x = 'ローカル';
関数 g() {
アラート(x); ();
}
f(); // 'local'


f() が呼び出されるとき、スコープ チェーンは呼び出しを含む 2 つの部分で構成されると理解できます。 f オブジェクトの後にグローバル オブジェクトが続きます。このとき、x の値を検索する場合は、まず f の呼び出しオブジェクトから検索され、見つからない場合は後続のグローバル オブジェクト内で x が検索されます。同様に、g は f の入れ子関数であるため、g が呼び出されるとき、スコープ チェーンは、g の呼び出しオブジェクト、f の呼び出しオブジェクト、およびグローバル オブジェクトの 3 つの部分で構成される必要があります。関数 g は x の値を出力するため、最初に g の呼び出しオブジェクトで x の値を検索します。次に、周辺の f 呼び出しオブジェクトで x の定義を検索します。 find x='local' の場合、グローバル オブジェクトの検索を続行する代わりに x を出力します。 x の値が f で定義されていない場合、スコープ チェーンの背後にあるグローバル オブジェクトの検索が続行され、結果はグローバルになります。グローバルオブジェクトで定義されていない場合は、当然未定義になります。
スコープ チェーンについては予備的に理解しましたが、同時に、クロージャには 2 つの一般的な用途があることもわかりました。1 つはローカル変数にアクセスするために使用できるということです。フィールド内の変数値はメモリに保存され、関数呼び出しが完了した後も破棄されません。
次に、クロージャが外部変数の値をメモリに保存できる理由を理解するのに役立つ、ありふれた例を見てみましょう。


function makeFunc (x) {
return function ( ) {return x }
}
var a = [makeFunc(0), makeFunc(1), makeFunc(2)];
alert(a[0]()); >alert( a[1]());
alert(a[2]());


実行結果は 0,1,2 です。字句スコープの厳密な通常の動作。各 makeFunc 呼び出しが完了すると、その呼び出し元オブジェクトはスコープ チェーンから削除され、そのオブジェクトへの参照はなくなり、最終的にはガベージ コレクションを通じて完了します。もっと詳しく言うと、このように理解できます。
makeFunc が呼び出されるたびに、呼び出し元のオブジェクトが作成され、スコープ チェーンに配置されます。関数 makeFunc の場合、呼び出し元オブジェクトには属性が含まれます。関数が実行されると、呼び出し元オブジェクトが作成され、スコープ チェーンに配置されます (注: 関数には x の定義がありません)。無名関数の呼び出しオブジェクトなので、その周囲の関数を参照します。 makeFunc の呼び出しオブジェクト (アクセスします。呼び出し元のオブジェクトには x が含まれているため、x が破棄されると x も破棄されます。保存されません。
上記は関数の詳細な実行プロセスです。よく理解して、以下の変更されたコードを見てください:



コードをコピー コードは次のとおりです: var x = 0;
function makeFunc () {
return function () {return x }
}
var a = [ makeFunc()、makeFunc()、makeFunc()];
alert(a[0]());
alert(a[2]()); );


x はグローバル変数であり、実行結果は 0、1、2 ですが、この結果は上記とは多少異なります。次に、スコープチェーンの観点からこの結果の理由を理解します。
同様に、makeFunc が呼び出されるたびに、内部の入れ子関数への参照が返されるため、呼び出し元オブジェクトがスコープ チェーンに作成され、内部の入れ子関数が実行を開始し、入れ子関数の呼び出しオブジェクトを作成します。スコープチェーン。次に、x の値を返します。ここでは、入れ子になった関数の呼び出しオブジェクトには x がなく、その周囲の makeFunc の呼び出しオブジェクトには x がありません。検索できるのはグローバル オブジェクトまでだけです。グローバル オブジェクト内で x の定義が見つかったので、通常どおり実行され、x の値が返され、x が 1 ずつ増分され、ネストされた関数が完了し、呼び出し元のオブジェクトが削除され、makeFunc が完了します。呼び出し元のオブジェクトも削除されますが、呼び出し元のオブジェクトには x がないため、呼び出し元のオブジェクトの破棄は x にまったく影響しません。その結果、グローバル変数 x の値の変更が保存されます。
外部呼び出しオブジェクトへの上記のアクセスは理解を助けるためのものであり、厳密なものではないことに注意してください。ただし、JavaScript が定義するプロパティはスコープ チェーンの一部です。呼び出しオブジェクトはまだ「生きています」。さらに、周辺関数にグローバル オブジェクトへの参照を持つ 2 つ以上の入れ子関数が含まれている場合、これらの入れ子関数はすべて同じグローバル呼び出しオブジェクトを共有し、そのうちの 1 つによるグローバル オブジェクトへの変更は他の関数にも表示されます。の。
JavaScript では、関数は、実行されるコードと、これらのコードが実行されるスコープで構成される複合体です。大まかに言えば、このコードとスコープの複合体をクロージャーと呼ぶことができます。
【終わり】
変数の値を記憶するために呼び出す必要がある関数を記述する必要がある場合があります。したがって、スコープを理解していれば、関数の呼び出しオブジェクトは呼び出し後に維持できないため、ローカル変数を実現するのが難しいことがわかります。上の例のように、グローバル変数でこれを行うことができますが、これは簡単にグローバル変数汚染を引き起こす可能性があります。呼び出し元のオブジェクトは維持できないので、呼び出し元のオブジェクトに値を保存すればよいのではないでしょうか? !したがって、これを行う 1 つの方法は、関数オブジェクト自体のプロパティとともに保存することです。
コードをコピー コードは次のとおりです。

uniqueID = function () {
if (! argument.callee.id) argument.callee.id = 0;
return argument.callee.id ;
alert(uniqueID()); //0
alert(uniqueID) ()) ; //1

上記のように、関数自体はオブジェクトなので、独自の属性の 1 つを付けて保存することは可能ですが、これには問題があります。つまり、誰でもいつでも保存できます。 unqueID.id を通じて最初に保存した値に強制的にアクセスし、変更を加えることができます。これは私たちが見たくないものです。
したがって、通常、これを達成するためにクロージャを使用します。次のように:

コードをコピー コードは次のとおりです:
_uniqueID = (function() {
var id = 0;
return function () {return id }
})();
alert(_uniqueID()) //0
alert(_uniqueID()); ; //1

同様に、use ドメインを使用して結果を説明します。 _uniqueID 自体は匿名関数であり、その中に匿名の入れ子関数があることに注意してください。直接呼び出すのは _uniqueID() です。つまり、直接呼び出すのは実際には _uniqueID 内の入れ子関数であり、それが呼び出し元のオブジェクトです。それ自体は ID を定義しないため、周囲の呼び出しオブジェクトの ID を参照し、それを返します。ID は 1 ずつ増加します。実行が完了すると、内側のネストされた関数呼び出しオブジェクトはスコープ チェーンの外に移動します。ペリフェラルIDは破壊されていなかったので、このように保存されました。
混乱している人もいるかもしれませんが、関数の実行後に呼び出し元のオブジェクトがスコープ チェーンを削除したということではないでしょうか?呼び出し元のオブジェクトにはあってはならないのです。
はい、呼び出し元のオブジェクトは現在の関数が実行された後に参照を終了しますが、上記の _uniqueID() 呼び出しは直接呼び出された周辺関数ではなく、ネストされた関数が呼び出されたものであることを誤解しないでください。関数のセットには、周囲の関数のスコープ チェーンが含まれます。したがって、呼び出し元のオブジェクトがスコープ チェーンを削除すると、このスコープ チェーン内の他のオブジェクトのプロパティにアクセスして変更できます。
クロージング自体は理解するのが難しいですが、困っている人の助けになれば幸いです。また、資格が限られているため、私の理解が間違っている可能性があります。見つけた場合は修正してください。
声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
一文浅析Golang中的闭包一文浅析Golang中的闭包Nov 21, 2022 pm 08:36 PM

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。 换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。 闭包会随着函数的创建而被同时创建。

python闭包有哪些python闭包有哪些Oct 30, 2023 pm 04:53 PM

python闭包主要包括函数闭包和装饰器闭包。详细介绍:1、函数闭包是指在一个函数内部返回另一个函数,并且返回的函数能够访问到其内部变量。这样的返回函数就是函数闭包,函数闭包在程序中可以被反复使用,因此可以用来实现一些功能上的封装;2、装饰器闭包是指在使用装饰器时,被装饰的函数并没有直接被调用,而是被包装在一个函数内部,并返回一个新的函数。这个新的函数就是一个装饰器闭包等等。

如何利用PHP7的匿名函数和闭包实现更加灵活的代码逻辑处理?如何利用PHP7的匿名函数和闭包实现更加灵活的代码逻辑处理?Oct 21, 2023 am 10:21 AM

如何利用PHP7的匿名函数和闭包实现更加灵活的代码逻辑处理?在PHP7之前,我们经常使用函数来封装一段特定的逻辑,然后在代码中调用这些函数来实现特定的功能。然而,有时候我们可能需要在代码中定义一些临时的逻辑块,这些逻辑块没有必要创建一个独立的函数,同时又不想在代码中引入太多的全局变量。PHP7引入了匿名函数和闭包,可以很好地解决这个问题。匿名函数是一种没有名

Python中的闭包是如何实现的?Python中的闭包是如何实现的?Oct 21, 2023 am 10:33 AM

Python中的闭包是如何实现的?闭包是一种函数内部定义的函数,并且在函数内部引用了外部函数的变量。这种特性使得内部函数可以访问外部函数的变量,并且在外部函数执行完毕后,闭包仍然可以访问和操作外部函数的变量。闭包在Python中通过以下几个步骤来实现:定义外部函数,并在其中定义内部函数:首先,我们需要在外部函数内部定义一个内部函数。这个内部函数即是闭包。de

react有哪些闭包react有哪些闭包Oct 27, 2023 pm 03:11 PM

react有事件处理函数、useEffect和useCallback、高阶组件等等闭包。详细介绍:1、事件处理函数闭包:在React中,当我们在组件中定义一个事件处理函数时,该函数会形成一个闭包,可以访问组件作用域内的状态和属性。这样可以在事件处理函数中使用组件的状态和属性,实现交互逻辑;2、useEffect和useCallback中的闭包等等。

如何使用PHP7的匿名函数和闭包实现更加灵活和可复用的代码逻辑?如何使用PHP7的匿名函数和闭包实现更加灵活和可复用的代码逻辑?Oct 24, 2023 am 10:30 AM

如何使用PHP7的匿名函数和闭包实现更加灵活和可复用的代码逻辑?在PHP编程领域中,匿名函数和闭包是非常有价值和强大的工具。PHP7引入了一些新的语言特性,使得使用匿名函数和闭包更加方便和灵活。本文将介绍如何使用PHP7的匿名函数和闭包来实现更加灵活和可复用的代码逻辑,并提供一些具体的代码示例。一、匿名函数匿名函数是一种没有名称的函数。在PHP中,可以将匿名

怎么样减少闭包的产生怎么样减少闭包的产生Oct 27, 2023 pm 04:28 PM

减少闭包产生的方法有避免不必要的闭包、控制闭包的返回值、使用弱引用、减少不必要的全局变量、合理使用循环和递归、使用事件代理、编写单元测试、遵循设计原则和使用工具进行代码分析等。详细介绍:1、避免不必要的闭包,在很多情况下,闭包并非必需的,可以用模块模式来实现私有变量,避免使用闭包;2、控制闭包的返回值,在使用闭包时,应该尽量控制闭包的返回值,如果闭包返回的是基本数据类型等等。

如何解决Python的闭包错误?如何解决Python的闭包错误?Jun 24, 2023 pm 11:23 PM

Python是一种非常流行的编程语言,因为它非常易学易用,同时也具备了强大的功能。其中,闭包是Python中的一种函数,它可以在函数的内部定义另一个函数,并返回这个函数作为函数的返回值。尽管闭包非常方便,但有时会出现某些错误,比如闭包错误。本文将介绍如何解决Python的闭包错误。初步了解闭包在Python中,闭包是由一个内部函数和一个定义在内部函数之外的函

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

AI Hentai Generator

AI Hentai Generator

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

ホットツール

SublimeText3 中国語版

SublimeText3 中国語版

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

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

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