ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript の匿名関数と自己実行

JavaScript の匿名関数と自己実行

高洛峰
高洛峰オリジナル
2016-10-13 10:21:31981ブラウズ

関数の定義は大きく 3 つの方法に分けることができます:

1 つ目: これも最も一般的な方法です

function double(x){    
    return 2 * x;       
}

2 つ目: このメソッドは Function コンストラクターを使用し、パラメーター リストと関数本体の両方を次のように受け取ります文字列は非常に不便なので、使用はお勧めしません。

var double = new Function('x', 'return 2 * x;');

3 番目のタイプ:

var double = function(x) { return 2* x; }

「=」の右側の関数は、関数を作成した後、変数 square に代入されることに注意してください。

匿名関数の作成

最初の方法: 上で述べたように二乗関数を定義します。これも最も一般的に使用される方法の 1 つです。

2 番目の方法:

(function(x, y){   
    alert(x + y);     
})(2, 3);

ここ (最初の括弧内) で匿名関数が作成され、2 番目の括弧を使用して匿名関数を呼び出し、パラメーターを渡します。括弧は式であり、式には戻り値があるため、最後に括弧のペアを追加して実行させることができます

1. 自己実行匿名関数とは何ですか。 function?

これは次のような関数を指します: (function {// code})();

2. 質問

function {// code})(); が実行できるのはなぜですか。 / code} (); しかし、エラーが報告されますか?

3. 分析

(1) まず、この 2 つの違いを理解する必要があります:
(関数 {// コード}) は式、関数 { // code} は関数宣言です。
(2) 次に、js の「プリコンパイル」の特徴:
「プリコンパイル」段階では、js は関数宣言を解釈しますが、
の場合は無視されます。 function() {// code}(); に対して実行されます。function() {//code} は「コンパイル前」段階で解釈されているため、js は function(){//code} をスキップして実行を試みます(); なのでエラーが報告されます ;
js が (function {// code})(); を実行すると、(function {// code}) は式であるため、js はそれを解決して戻り値を取得します。戻り値は関数なので、(); が見つかった場合、それが実行されます

また、関数を式に変換する方法は、必ずしもグループ化演算子 () に依存するわけではありません。 void 演算子、~ 演算子、! 演算子...…

例:

!function(){   
  alert("另类的匿名函数自执行");   
}();

匿名関数とクロージャ

クロージャを表す英語はクロージャです。クロージャを使用するため、これは JavaScript の知識の非常に重要な部分です。コードの量を大幅に削減し、コードをより明確に見せることができます。つまり、この関数は非常に強力です。

クロージャの意味: 端的に言えば、クロージャは関数の入れ子です。外側の関数が実行された場合でも、内側の関数は外側の関数のすべての変数を使用できます (これには JavaScript スコープ チェーンが関係します)。

function checkClosure(){  
    var str = 'rain-man';  
    setTimeout(  
        function(){ alert(str); } //这是一个匿名函数  
    , 2000);  
}  
checkClosure();

この例は非常に単純に見えますが、実行プロセスを注意深く分析すると、まだ多くの知識ポイントがあります。checkClosure 関数の実行は瞬時に行われ (おそらく 0.00001 ミリ秒しかかかりません)、変数 str が関数内に作成されます。 checkClosure の本体、 setTimeout の匿名関数が str への参照を持っているため、 str は checkClosure の実行後に解放されません。 2 秒後、関数本体内の匿名関数が実行され、str が解放されます。

クロージャを使用してコードを最適化する:

function forTimeout(x, y){  
    alert(x + y);  
}  
function delay(x , y  , time){  
    setTimeout('forTimeout(' +  x + ',' +  y + ')' , time);      
}  
/**  
 * 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰  
 * function delay(x , y , time){  
 *     setTimeout(  
 *         function(){  
 *             forTimeout(x , y)   
 *         }            
 *     , time);     
 * }  
 */

匿名関数の最大の用途は、クロージャ (これは JavaScript 言語の機能の 1 つ) を作成することです。また、名前空間を構築してグローバル変数の使用を減らすこともできます。

var oEvent = {};  
(function(){   
    var addEvent = function(){ /*代码的实现省略了*/ };  
    function removeEvent(){}  
     
    oEvent.addEvent = addEvent;  
    oEvent.removeEvent = removeEvent;  
})();

このコードでは、関数 addEvent と RemoveEvent はどちらもローカル変数ですが、グローバル変数 oEvent を通じて使用できます。これにより、グローバル変数の使用が大幅に削減され、Web ページのセキュリティが強化されます。 次のコードを使用します: oEvent.addEvent(document.getElementById('box'), 'click', function(){});

var rainman = (function(x , y){  
    return x + y;  
})(2 , 3);  
/**  
 * 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。  
 * var rainman = function(x , y){  
 *    return x + y;  
 * }(2 , 3);

ここでは、変数 Rainman を作成し、匿名関数を直接呼び出します。 5 に初期化されます。この小さなトリックは時々非常に役立ちます。

var outer = null;  
     
(function(){  
    var one = 1;  
    function inner (){  
        one += 1;  
        alert(one);  
    }  
    outer = inner;  
})();  
     
outer();    //2  
outer();    //3  
outer();    //4

このコードの変数 1 はローカル変数 (関数内で定義されているため) なので、外部からアクセスすることはできません。ただし、ここでは変数 one にアクセスできる inner 関数を作成し、グローバル変数 external は inner を参照するため、outer を 3 回呼び出すと増分結果がポップアップされます。

1 クロージャにより、内部関数は親関数内の変数を参照できますが、変数は最終値です

/**  
 * <body>  
 * <ul>  
 *     <li>one</li>  
 *     <li>two</li>  
 *     <li>three</li>  
 *     <li>one</li>  
 * </ul>  
 */
     
var lists = document.getElementsByTagName(&#39;li&#39;);  
for(var i = 0 , len = lists.length ; i < len ; i++){  
    lists[ i ].onmouseover = function(){  
        alert(i);      
    };  
}

マウスを各

要素上に移動すると、期待していた要素の添字ではなく、常に 4 が表示されます。どうしてこれなの?注意事項(最終値)に記載済みです。明らかに、この説明は単純すぎます。mouseover イベントが listen 関数を呼び出すと、まず匿名関数 (function(){alert(i); }) 内を検索して、i が定義されているかどうかを確認します。 ; したがって、上方向に検索して検索します。結果は定義されており、i の値は 4 (ループ後の i の値) であるため、最終的には毎回 4 が表示されます。

解決策 1:

var lists = document.getElementsByTagName(&#39;li&#39;);  
for(var i = 0 , len = lists.length ; i < len ; i++){  
    (function(index){  
        lists[ index ].onmouseover = function(){  
            alert(index);      
        };                      
    })(i);  
}

解決策 2:

var lists = document.getElementsByTagName(&#39;li&#39;);  
for(var i = 0, len = lists.length; i < len; i++){  
    lists[ i ].$$index = i;    //通过在Dom元素上绑定$$index属性记录下标  
    lists[ i ].onmouseover = function(){  
        alert(this.$$index);      
    };  
}

2 メモリ リーク

  • クロージャを使用すると、ブラウザでメモリ リークが発生しやすくなります

  • 声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。