茄子在线看片免费人成视频,午夜福利精品a在线观看,国产高清自产拍在线观看,久久综合久久狠狠综合

    <s id="ddbnn"></s>
  • <sub id="ddbnn"><ol id="ddbnn"></ol></sub>

  • <legend id="ddbnn"></legend><s id="ddbnn"></s>

    深入解析JavaScript中的立即執(zhí)行函數(shù)
    來源:易賢網(wǎng) 閱讀:972 次 日期:2016-06-25 13:30:31
    溫馨提示:易賢網(wǎng)小編為您整理了“深入解析JavaScript中的立即執(zhí)行函數(shù)”,方便廣大網(wǎng)友查閱!

    立即執(zhí)行函數(shù)模式在JavaScript中可以讓你的函數(shù)在定義后立即被執(zhí)行,下面我們就來深入解析JavaScript中的立即執(zhí)行函數(shù),需要的朋友可以參考下

    它是什么

    在 JavaScript 里,每個函數(shù),當被調(diào)用時,都會創(chuàng)建一個新的執(zhí)行上下文。因為在函數(shù)里定義的變量和函數(shù)是唯一在內(nèi)部被訪問的變量,而不是在外部被訪問的變量,當調(diào)用函數(shù)時,函數(shù)提供的上下文提供了一個非常簡單的方法創(chuàng)建私有變量。

    function makeCounter() {

      var i = 0;

      return function(){

        console.log(++i);

      };  

    }

    //記?。篳counter`和`counter2`都有他們自己的變量 `i`

    var counter = makeCounter();

    counter();//1

    counter();//2

    var counter2 = makeCounter();

    counter2();//1

    counter2();//2

    i;//ReferenceError: i is not defined(它只存在于makeCounter里)

    在許多情況下,你可能并不需要makeWhatever這樣的函數(shù)返回多次累加值,并且可以只調(diào)用一次得到一個單一的值,在其他一些情況里,你甚至不需要明確的知道返回值。

    它的核心

    現(xiàn)在,無論你定義一個函數(shù)像這樣function foo(){}或者var foo = function(){},調(diào)用時,你都需要在后面加上一對圓括號,像這樣foo()。

    //向下面這樣定義的函數(shù)可以通過在函數(shù)名后加一對括號進行調(diào)用,像這樣`foo()`,

    //因為foo相對于函數(shù)表達式`function(){/* code */}`只是一個引用變量

    var foo = function(){/* code */}

    //那這可以說明函數(shù)表達式可以通過在其后加上一對括號自己調(diào)用自己嗎?

    function(){ /* code */}(); //SyntaxError: Unexpected token (

    正如你所看到的,這里捕獲了一個錯誤。當圓括號為了調(diào)用函數(shù)出現(xiàn)在函數(shù)后面時,無論在全局環(huán)境或者局部環(huán)境里遇到了這樣的function關(guān)鍵字,默認的,它會將它當作是一個函數(shù)聲明,而不是函數(shù)表達式,如果你不明確的告訴圓括號它是一個表達式,它會將其當作沒有名字的函數(shù)聲明并且拋出一個錯誤,因為函數(shù)聲明需要一個名字。

    問題1:這里我么可以思考一個問題,我們是不是也可以像這樣直接調(diào)用函數(shù) var foo = function(){console.log(1)}(),答案是可以的。

    問題2:同樣的,我們還可以思考一個問題,像這樣的函數(shù)聲明在后面加上圓括號被直接調(diào)用,又會出現(xiàn)什么情況呢?請看下面的解答。

    函數(shù),圓括號,錯誤

    有趣的是,如果你為一個函數(shù)指定一個名字并在它后面放一對圓括號,同樣的也會拋出錯誤,但這次是因為另外一個原因。當圓括號放在一個函數(shù)表達式后面指明了這是一個被調(diào)用的函數(shù),而圓括號放在一個聲明后面便意味著完全的和前面的函數(shù)聲明分開了,此時圓括號只是一個簡單的代表一個括號(用來控制運算優(yōu)先的括號)。

    //然而函數(shù)聲明語法上是無效的,它仍然是一個聲明,緊跟著的圓括號是無效的,因為圓括號里需要包含表達式

    function foo(){ /* code */ }();//SyntaxError: Unexpected token

    //現(xiàn)在,你把一個表達式放在圓括號里,沒有拋出錯誤...,但是函數(shù)也并沒有執(zhí)行,因為:

    function foo(){/* code */}(1)

    //它等同于如下,一個函數(shù)聲明跟著一個完全沒有關(guān)系的表達式:

    function foo(){/* code */}

    (1);

    立即執(zhí)行函數(shù)表達式(IIFE)

    幸運的是,修正語法錯誤很簡單。最流行的也最被接受的方法是將函數(shù)聲明包裹在圓括號里來告訴語法分析器去表達一個函數(shù)表達式,因為在Javascript里,圓括號不能包含聲明。因為這點,當圓括號為了包裹函數(shù)碰上了 function關(guān)鍵詞,它便知道將它作為一個函數(shù)表達式去解析而不是函數(shù)聲明。注意理解這里的圓括號和上面的圓括號遇到函數(shù)時的表現(xiàn)是不一樣的,也就是說。

    當圓括號出現(xiàn)在匿名函數(shù)的末尾想要調(diào)用函數(shù)時,它會默認將函數(shù)當成是函數(shù)聲明。

    當圓括號包裹函數(shù)時,它會默認將函數(shù)作為表達式去解析,而不是函數(shù)聲明。

    //這兩種模式都可以被用來立即調(diào)用一個函數(shù)表達式,利用函數(shù)的執(zhí)行來創(chuàng)造私有變量

    (function(){/* code */}());//Crockford recommends this one,括號內(nèi)的表達式代表函數(shù)立即調(diào)用表達式

    (function(){/* code */})();//But this one works just as well,括號內(nèi)的表達式代表函數(shù)表達式

    // Because the point of the parens or coercing operators is to disambiguate

    // between function expressions and function declarations, they can be

    // omitted when the parser already expects an expression (but please see the

    // "important note" below).

    var i = function(){return 10;}();

    true && function(){/*code*/}();

    0,function(){}();

    //如果你并不關(guān)心返回值,或者讓你的代碼盡可能的易讀,你可以通過在你的函數(shù)前面帶上一個一元操作符來存儲字節(jié)

    !function(){/* code */}();

    ~function(){/* code */}();

    -function(){/* code */}();

    +function(){/* code */}();

    // Here's another variation, from @kuvos - I'm not sure of the performance

    // implications, if any, of using the `new` keyword, but it works.

    // http://twitter.com/kuvos/status/18209252090847232

    new function(){ /* code */ }

    new function(){ /* code */ }() // Only need parens if passing arguments

    關(guān)于括號的重要筆記

    在一些情況下,當額外的帶著歧義的括號圍繞在函數(shù)表達式周圍是沒有必要的(因為這時候的括號已經(jīng)將其作為一個表達式去表達),但當括號用于調(diào)用函數(shù)表達式時,這仍然是一個好主意。

    這樣的括號指明函數(shù)表達式將會被立即調(diào)用,并且變量將會儲存函數(shù)的結(jié)果,而不是函數(shù)本身。當這是一個非常長的函數(shù)表達式時,這可以節(jié)約比人閱讀你代碼的時間,不用滾到頁面底部去看這個函數(shù)是否被調(diào)用。

    作為規(guī)則,當你書寫清楚明晰的代碼時,有必要阻止 JavaScript 拋出錯誤的,同樣也有必要阻止其他開發(fā)者對你拋出錯誤 WTFError!

    保存閉包的狀態(tài)

    就像當函數(shù)通過他們的名字被調(diào)用時,參數(shù)會被傳遞,而當函數(shù)表達式被立即調(diào)用時,參數(shù)也會被傳遞。一個立即調(diào)用的函數(shù)表達式可以用來鎖定值并且有效的保存此時的狀態(tài),因為任何定義在一個函數(shù)內(nèi)的函數(shù)都可以使用外面函數(shù)傳遞進來的參數(shù)和變量(這種關(guān)系被叫做閉包)。

    // 它的運行原理可能并不像你想的那樣,因為`i`的值從來沒有被鎖定。

    // 相反的,每個鏈接,當被點擊時(循環(huán)已經(jīng)被很好的執(zhí)行完畢),因此會彈出所有元素的總數(shù),

    // 因為這是 `i` 此時的真實值。

    var elems = document.getElementsByTagName('a');

    for(var i = 0;i < elems.length; i++ ) {

      elems[i].addEventListener('click',function(e){

        e.preventDefault();

        alert('I am link #' + i)

        },false);

    }

    // 而像下面這樣改寫,便可以了,因為在IIFE里,`i`值被鎖定在了`lockedInIndex`里。

    // 在循環(huán)結(jié)束執(zhí)行時,盡管`i`值的數(shù)值是所有元素的總和,但每一次函數(shù)表達式被調(diào)用時,

    // IIFE 里的 `lockedInIndex` 值都是`i`傳給它的值,所以當鏈接被點擊時,正確的值被彈出。

    var elems = document.getElementsByTagName('a');

    for(var i = 0;i < elems.length;i++) {

      (function(lockedInIndex){

        elems[i].addEventListener('click',function(e){

          e.preventDefault();

          alert('I am link #' + lockedInIndex);

          },false)

      })(i);

    }

    //你同樣可以像下面這樣使用IIFE,僅僅只用括號包括點擊處理函數(shù),并不包含整個`addEventListener`。

    //無論用哪種方式,這兩個例子都可以用IIFE將值鎖定,不過我發(fā)現(xiàn)前面一個例子更可讀

    var elems = document.getElementsByTagName( 'a' );

    for ( var i = 0; i < elems.length; i++ ) {

      elems[ i ].addEventListener( 'click', (function( lockedInIndex ){

        return function(e){

          e.preventDefault();

          alert( 'I am link #' + lockedInIndex );

        };

        })( i ),false);

      }

    記住,在這最后兩個例子里,lockedInIndex可以沒有任何問題的訪問i,但是作為函數(shù)的參數(shù)使用一個不同的命名標識符可以使概念更加容易的被解釋。

    立即執(zhí)行函數(shù)一個最顯著的優(yōu)勢是就算它沒有命名或者說是匿名,函數(shù)表達式也可以在沒有使用標識符的情況下被立即調(diào)用,一個閉包也可以在沒有當前變量污染的情況下被使用。

    自執(zhí)行匿名函數(shù)(“Self-executing anonymous function”)有什么問題呢?

    你看到它已經(jīng)被提到好幾次了,但是它仍然不是那么清楚的被解釋,我提議將術(shù)語改成"Immediately-Invoked Function Expression",或者,IIFE,如果你喜歡縮寫的話。

    什么是Immediately-Invoked Function Expression呢?它使一個被立即調(diào)用的函數(shù)表達式。就像引導你去調(diào)用的函數(shù)表達式。

    我想Javascript社區(qū)的成員應該可以在他們的文章里或者陳述里接受術(shù)語,Immediately-Invoked Function Expression和 IIFE,因為我感覺這樣更容易讓這個概念被理解,并且術(shù)語"self-executing anonymous function"真的也不夠精確。

    //下面是個自執(zhí)行函數(shù),遞歸的調(diào)用自己本身

    function foo(){foo();};

    //這是一個自執(zhí)行匿名函數(shù)。因為它沒有標識符,它必須是使用`arguments.callee`屬性來調(diào)用它自己

    var foo = function(){arguments.callee();};

    //這也許算是一個自執(zhí)行匿名函數(shù),但是僅僅當`foo`標識符作為它的引用時,如果你將它換成用`foo`來調(diào)用同樣可行

    var foo = function(){foo();};

    //有些人像這樣叫'self-executing anonymous function'下面的函數(shù),即使它不是自執(zhí)行的,因為它并沒有調(diào)用它自己。然后,它只是被立即調(diào)用了而已。

    (function(){ /*code*/ }());

    //為函數(shù)表達式增加標識符(也就是說創(chuàng)造一個命名函數(shù))對我們的調(diào)試會有很大幫助。一旦命名,函數(shù)將不再匿名。

    (function foo(){/* code */}());

    //IIFEs同樣也可以自執(zhí)行,盡管,也許他不是最有用的模式

    (function(){arguments.callee();}())

    (function foo(){foo();}())

    // One last thing to note: this will cause an error in BlackBerry 5, because

    // inside a named function expression, that name is undefined. Awesome, huh?

    (function foo(){ foo(); }());

    希望上面的例子可以讓你更加清楚的知道術(shù)語'self-executing'是有一些誤導的,因為他并不是執(zhí)行自己的函數(shù),盡管函數(shù)已經(jīng)被執(zhí)行。同樣的,匿名函數(shù)也沒用必要特別指出,因為,Immediately Invoked Function Expression,既可以是命名函數(shù)也可以匿名函數(shù)。

    最后:模塊模式

    當我調(diào)用函數(shù)表達式時,如果我不至少一次的提醒我自己關(guān)于模塊模式,我便很可能會忽略它。如果你并不屬性 JavaScript 里的模塊模式,它和我下面的例子很像,但是返回值用對象代替了函數(shù)。

    var counter = (function(){

      var i = 0;

      return {

        get: function(){

          return i;

        },

        set: function(val){

          i = val;

        },

        increment: function(){

          return ++i;

        }

      }

      }());

      counter.get();//0

      counter.set(3);

      counter.increment();//4

      counter.increment();//5

      conuter.i;//undefined (`i` is not a property of the returned object)

      i;//ReferenceError: i is not defined (it only exists inside the closure)

    模塊模式方法不僅相當?shù)膮柡Χ液唵?。非常少的代碼,你可以有效的利用與方法和屬性相關(guān)的命名,在一個對象里,組織全部的模塊代碼即最小化了全局變量的污染也創(chuàng)造了使用變量。

    更多信息請查看網(wǎng)絡編程
    易賢網(wǎng)手機網(wǎng)站地址:深入解析JavaScript中的立即執(zhí)行函數(shù)

    2026上岸·考公考編培訓報班

    • 報班類型
    • 姓名
    • 手機號
    • 驗證碼
    關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
    工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
    聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
    咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)