ホームページ  >  記事  >  ウェブフロントエンド  >  Javascript の匿名関数と自己実行関数の簡単な分析_JavaScript スキル

Javascript の匿名関数と自己実行関数の簡単な分析_JavaScript スキル

WBOY
WBOYオリジナル
2016-05-16 15:16:001055ブラウズ

関数は JavaScript で最も柔軟なオブジェクトです。ここではその匿名関数の使用法のみを説明します。無名関数:関数名のない関数です。

関数の定義は大きく分けて次の 3 つの方法があります。

最初のタイプ: これも最も一般的なタイプです

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 {// code})();

2. 質問

(function {// code})(); は実行できるのに、function {// code}(); がエラーを報告するのはなぜですか?

3. 分析

(1) まず、この 2 つの違いを理解する必要があります。
(function {// code}) は式、function {// code} は関数宣言です。
(2) 次に、js の「プリコンパイル」の特徴:
js の「プリコンパイル」フェーズでは、関数宣言は解釈されますが、式は無視されます。
(3). 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 が関数本体に作成されます。 setTimeout の匿名関数が str への参照を持っているため、 checkClosure の実行後に str は解放されません。 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('li'); 
for(var i = 0 , len = lists.length ; i < len ; i++){ 
lists[ i ].onmouseover = function(){ 
alert(i); 
}; 
}

你会发现当鼠标移过每一个25edfb22a4f469ecb59f1190150159c6元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。

解决方法一:

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

解决方法二:

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

解决方法三:

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

2 内存泄露

使用闭包十分容易造成浏览器的内存泄露,严重情况下会是浏览器挂死

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