|
|
|
|
|
在JavaScript的函數調用時,常常見到 IIFE 這個詞,它其實是“立即調用函數表達式”的英文縮寫,在本文中,我將介紹什么是 IIFE,它與調用函數又有什么關系。
我們先看一個簡單的函數調用示例,隨后再介紹 IIFE 與函數調用的關系。
function hello(name) {
return 'Hello ' + name + '!';
}
// 函數調用
const message = hello('World');
hello('World')
就是一個函數調用。
何為函數調用?
我們可以這樣定義:
當計算結果為函數對象的表達式,后跟一對括號
()
,括號內用逗號,
分隔的參數表達式列表時,這就是函數調用。例如 parseInt('18')。
上面示例中,hello
表達式計算為一個函數對象,后跟一對帶World
參數的括號()
。
函數調用表達式不能是屬性訪問器 obj.myFunc()
,這是方法調用,例如[1,5].join(',')
不是函數調用,而是方法調用。請記住它們之間的區(qū)別。
函數調用示例
function myFunction(a, b) {
return a * b;
}
myFunction(10, 2); // 20
上面的函數不屬于任何對象。
在瀏覽器中,頁面對象是瀏覽器窗口。上面的函數自動變成了窗口函數。因此,myFunction()
和 window.myFunction()
是同一個函數:
function myFunction(a, b) {
return a * b;
}
window.myFunction(10, 2); // 20
何為 IIFE?
IIFE全稱是立即調用函數表達式(英文:immediately-invoked function expression,縮寫:IIFE),IIFE 也是一個函數調用。讓我們看一個 IIFE 的簡單例子:
// IIFE
const message = (function(name) {
return 'Hello ' + name + '!';
})('World');
第一對括號(function(name) {...})
是計算結果為函數對象的表達式,然后是一對帶'World
'參數的括號:('World')
。
IIFE 用法
立即調用函數表達式擁有數種不同的寫法。最常見的一種是將函數表達式字面量至于圓括號(分組運算符)之內,然后使用圓括號調用函數。
(function() {
// 這里的語句將獲得新的作用域
})();
若要將作用域外變量傳遞進函數,則按下述方式書寫:
(function(a, b) {
// a == 'hello'
// b == 'world'
})('hello', 'world');
開頭的括號可能會因為解釋器的分號自動插入特性造成一些問題。括號本用于明確字面量為表達式以與函數聲明語句區(qū)分,但解釋器可能將括號解釋為對以上一行中結尾的變量名為名的函數的調用。在一些省略分號的程序中,可見將分號至于行首的做法。這樣的分號被稱為“防御性分號”,舉例:
a = b + c
;(function() { // 故意將分號放在這里
// 代碼
})();
如此書寫,以防止語句被理解為對函數c的調用(c(...)
)。
IIFE 例子
理解立即調用函數表達式的關鍵在于認清JavaScript擁有函數作用域,但沒有塊作用域(ES6之前),且通過指針(而非復制)將變量傳入一個函數閉包。 ES6 引入了新關鍵字 let
和 const
,用它們定義的常量和變量具有塊級作用域。
缺少塊作用域意味著一個在類似于for循環(huán)的塊中聲明的變量會被置頂到其所包含的函數中。如果一個內部函數依賴于一個外部變量,而該外部變量被外部函數更改,那么執(zhí)行內函數就有些困難。舉例,我們在聲明函數之后,但在定義函數之前,改變一個變量的值。
var v, getValue;
v = 1;
getValue = function() { return v; };
v = 2;
getValue(); // 2
當我們手動給v
賦值時這結果似乎沒什么問題。不過,如果getValue()
是在一個循環(huán)中被定義的,那么就可能出現(xiàn)預想外的結果。
var v, getValue;
v = 1;
getValue = (function(x) {
return function() { return x; };
})(v);
v = 2;
getValue(); // 1
此例中,函數將 v
作為參數傳入并立即調用,保護了內部函數的執(zhí)行上下文。
立即調用函數表達式也可以用來創(chuàng)建私有方法來訪問函數,不僅起到保護作用,同時也暴露了一些可以后續(xù)使用的屬性。
// 'counter' 函數返回一個具有屬性的對象, 這里的屬性就是
// get set等函數
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
})();
// 這些調用使用了剛才counter得到的屬性
counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5
如果我們試圖從全局作用域直接訪問 counter.i
,會得到 undefined
,因為 i 這個數據由 IIFE 封裝,它并不是 counter
的屬性。同樣的,如果我們試圖訪問 i
也會收到錯誤,因為 i
并沒有在全局作用域中定義。
總結
本文介紹了JavaScript中的 IIFE 與函數調用,通過本文的學習,我們應該了解了函數調用的定義,知道 IIFE 也是函數調用的一種。
相關文章