JavaScript 閉包系列二(匿名函數及函數的閉包)

一. 匿名函數

1. 函數的定義,可分爲三種

1) 函數聲明方式html

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

2)Function構造函數,把參數列表和函數體都做爲字符串,不方便,不建議使用安全

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

3)函數表達式方式閉包

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

該形式中,等號右邊是一個匿名函數,建立函數完畢後,將該函數賦給了變量double。函數

2. 匿名函數

1)第一種方式this

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

等號右邊是一個匿名函數。注意匿名函數不能直接獨立的房子代碼中,以下代碼spa

functino(x) {
     return 2*x;
}                   // SyntaxError: Unexpected token (

2)第二種方式code

( function(x,y) {
    console.log(x+y);
})(2,3);

建立一個匿名函數(在第一個括號內),第二個括號用於調用該匿名函數並傳入參數。htm

 

二. 閉包(Closure)

閉包的含義:外層函數包含內層函數,內層函數能夠訪問外層函數的全部變量,即便外層函數執行完畢。(JavaScript做用域鏈)blog

題外話:上述對於閉包的解釋與《JavaScript 閉包系列一》中不徹底吻合。 上述解釋,閉包成立只需知足:函數inner嵌套在函數outer內部。另外一些文章對於閉包的解釋,閉包成立須要兩個條件:1)函數inner嵌套在函數outer內部;2)函數outer返回函數inner。對此,我已經凌亂了,各路大俠誰可以給個定論token

Example 1:

函數outer是瞬間執行的(約0.00001毫秒),在函數outer體內建立了一個變量str,在outer執行完畢後,str變量未被釋放,這是因爲setTimeout內的匿名函數存在對變量str的引用。等到2秒後,匿名函數執行完畢,str才被釋放。

function outer() {
     var str = "closure";
    setTimeout( function() {
        console.log(str);
    }, 2000);
}
outer();   // closure

Example 2:此例是否爲閉包呢?

function outer() {
     var i = 22;
    ( function inner() {
        console.log(i);
    })();
}
outer();   // 22

Example 3:簡化代碼

function forTimeout(x, y) {
    console.log(x + y);
}
function delay(x, y, time) {
    setTimeout('forTimeout(' + x + ',' + y + ')', time);
}
// 簡化後
function delay(x, y, time) {
    setTimeout(
         function() {
            forTimeout(x,y);
        }
    ,time);
}
delay(3, 4, 2000);  // 7


三. 匿名函數與閉包

匿名函數的最大用途是建立閉包,它也可用來構建命名空間,減小全局變量的使用。

Example1:

匿名函數中的addEvent和removeEvent爲局部變量,可是能夠經過全局變量oEvent使用它,大大減小了全局變量的使用,加強了網頁的安全性。

var oEvent = {};
( function() {
     var addEvent =  function() {};
     function removeEvent(){}

    oEvent.addEvent = addEvent;
    oEvent.removeEvent = removeEvent;
})();

Example2:

建立一個變量sun_mile_rain,並經過直接調用匿名函數初始化爲5,這種小技巧有時十分有用。

var sun_mile_rain = ( function(x , y){
     return x + y;
})(2 , 3);
console.log(sun_mile_rain);   // 5
//
也可以使用以下的方式,第一個括號只是幫助咱們閱讀,可是不推薦下面這種書寫格式
var sun_mile_rain =  function(x , y){
     return x + y;
}(2 , 3);

Example3:

代碼中,變量one定義在函數內部,是一個局部變量,所以外部是不能夠訪問的。但inner函數能夠訪問變量one,又將全局變量outer引用了inner,所以執行outer()能訪問到one的值。

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

換一種形式:函數fn執行,返回inner,將fn的執行結果賦給全局變量outer。執行outer也能訪問到one的值。所以可得知閉包的形式能夠有多種。

function fn() {
     var one = 1;
     function inner() {
        one += 1;
        console.log(one);
    }
     return inner;
}
var outer = fn();
outer();   // 2
outer();   // 3
outer();   // 4


四. 閉包與變量

閉包容許內層函數引用父函數中的變量,但該變量是最終值

鼠標移過每個li元素時,控制檯輸出的值都是3,而不是咱們指望的元素下標。當mouseover事件調用監聽函數時,首先在匿名函數內部查找i是否認義,結果沒找到,所以向上查找,在全局環境中找到i,而且i的值是3(循環後的值)。所以每次輸出的都是3。 

/*
<ul>
    <li>one</li>
    <li>two</li>
    <li>three</li>
</ul>
*/
var lists = document.getElementsByTagName("li");
for( var i=0; i<lists.length; i++) {
    lists[i].onmouseover =  function() {
        console.log(i);
    }
}

注意:此處的閉包,並非函數嵌套函數的形式,而是匿名函數包含在全局環境中的形式。

針對上述代碼,有三種方法改進,使得鼠標移動到li元素上時,控制檯輸出對應的下標值。

1)當即執行的匿名函數

var lists = document.getElementsByTagName("li");
for ( var i = 0; i < lists.length; i++) {
    ( function(index) {
        lists[i].onmouseover =  function() {
            console.log(index);
        };
    })(i);
}

 2)在DOM元素上綁定$$index屬性記錄下標

var lists = document.getElementsByTagName("li");
for ( var i = 0; i < lists.length; i++) {
    lists[i].$$index = i;
    lists[i].onmouseover =  function() {
        console.log( this.$$index);
    };
}

3)

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

 

 

 

時間:2014-10-23

地點:合肥

引用:http://www.cnblogs.com/rainman/archive/2009/05/04/1448899.html

相關文章
相關標籤/搜索