12個(gè)簡(jiǎn)單(但強(qiáng)大)的JavaScript技巧(二)
原文鏈接: 12 Simple (Yet Powerful) JavaScript Tips
其他鏈接: (譯文)12個(gè)簡(jiǎn)單(但強(qiáng)大)的JavaScript技巧(一)
強(qiáng)大的立即調(diào)用函數(shù)表達(dá)式
(什么是立即調(diào)用函數(shù)表達(dá)式, 何時(shí)使用它)
IIFE (Immediately Invoked Function Expressions, 發(fā)音:“Iffy”)是立即調(diào)用函數(shù)表達(dá)式的縮寫形式, 它的語(yǔ)法大概如下:
(function() {
//Do fun stuff
})()
這是一個(gè)立即調(diào)用的匿名函數(shù), 它在JavaScript中有一些特別重要的作用.
它是如何工作的?
包圍匿名函數(shù)的一對(duì)括號(hào)會(huì)把它變成函數(shù)表達(dá)式或者變量表達(dá)式.
-
這就相當(dāng)于:
//不帶括號(hào): ? = function() {}; //帶括號(hào): (? = function() {}); //函數(shù)被一個(gè)不知名的變量引用了, 一對(duì)括號(hào)把它包圍了, 把它變成了一個(gè)匿名的函數(shù)表達(dá)式同樣的, 我們甚至可以創(chuàng)建一個(gè)命名的立即調(diào)用函數(shù)表達(dá)式:
(showName = function(name) { console.log( name || "No Name"); })(); //No Name showName("Rich"); //Rich showName(); //NoName 記住, 當(dāng)你不用var關(guān)鍵詞創(chuàng)建變量的時(shí)候, JavaScript會(huì)自動(dòng)判斷該變量為全局變量. 在上面的例子中是沒有必要使用var關(guān)鍵詞的(因?yàn)槟阒罂赡軙?huì)調(diào)用它).
我們可以馬上或者在這之后使用這個(gè)函數(shù)
-
但是我們不可以在之后調(diào)用匿名函數(shù). 因?yàn)槌悄銊?chuàng)建匿名函數(shù)之后馬上調(diào)用, 在這之后沒有其他辦法可以引用它. 這是匿名函數(shù)只可以馬上調(diào)用它的原因.
當(dāng)把匿名函數(shù)包含在一對(duì)括號(hào)里面時(shí)(字面量), 整個(gè)字面量會(huì)被運(yùn)算,并且返回匿名函數(shù)的返回值. 它的返回值實(shí)質(zhì)上是整個(gè)匿名函數(shù)自身, 所以我們只需要在這之后加上一對(duì)括號(hào)來馬上調(diào)用它.
因此, 后面的一對(duì)括號(hào)等于告訴JavaScript編譯器馬上調(diào)用這個(gè)匿名函數(shù), 所以它才會(huì)被稱之為"立即調(diào)用函數(shù)表達(dá)式".
因?yàn)镴avaScript基于函數(shù)塊的作用域規(guī)則, 在匿名函數(shù)內(nèi)聲明變量都是局部變量, 所以這些局部變量沒辦法直接從外部獲取.
就像其他函數(shù)一樣, 你可以向匿名函數(shù)設(shè)定參數(shù)和傳遞變量. 你可以根據(jù)這個(gè)特性, 利用匿名函數(shù)的作用域擴(kuò)展它外圍函數(shù)的作用域(即閉包).
什么時(shí)候應(yīng)該使用它?
-
避免污染全局作用域
IIFE最廣泛的用途是避免污染全局作用域. 已經(jīng)有很多JavaScript庫(kù)和JavaScript高手正在使用這種技巧, 尤其是在最流行jQuery插件的開發(fā)者中. 你也應(yīng)該把這個(gè)技巧應(yīng)用在你的程序的主要文件中(main.js).
在這個(gè)例子中, 我使用了匿名函數(shù)把所有全局作用域的變量變成了局部變量, 所以現(xiàn)在全局作用域中還可以定義新的變量, 不用顧忌是否會(huì)和匿名函數(shù)內(nèi)的變量在變量名上發(fā)生沖突(還包括其他庫(kù)或者框架):
//所有的代碼包含在立即調(diào)用函數(shù)中 (function() { var firstName = "Richard"; funtion init() { doStuff(firstName); //在這里開始插入應(yīng)用程序的代碼... } function doStuff() { //... } function doMoreStuff() { //... } //啟動(dòng)應(yīng)用程序; init(); })(); -
用作條件選擇器
這種使用方式還沒有被廣泛所知, 但它是相當(dāng)強(qiáng)大的. 你可以不調(diào)用一個(gè)命名函數(shù)來處理復(fù)雜的運(yùn)算的.
注意在三目運(yùn)算符(..
?..:.. )中的兩個(gè)匿名函數(shù)我盡可能多地加入空白來使語(yǔ)句看起來更容易理解
var unnamedDocs = [], namedDocs = ['a_bridge_runover', 'great_dreamers']; function createDoc(documentTitle) { var documentName = documentTitle ? (function(theName) { var newNamedDoc = theName.toLocaleLowerCase().replace('', '_'); nameDocs.push(newNamedDoc); return newNamedDoc; })(documentTitle) : (function() { var newUnnamedDoc = 'untitled_' + Number(namedDocs.length + 1); unnamedDocs.push(newUnnamedDoc); return newUnnamedDoc; })(); return documentName; } createDoc('Over The Rainbow'); //over_the rainbow createDoc(); //untitled_4