JS自執(zhí)行函數(shù)又稱為IIFE,在我們開發(fā)過程中會使用到大量的自執(zhí)行函數(shù)。
IIFE寫法:
使用建議:在使用只執(zhí)行函數(shù)前面加上 “ ; ”,避免壓縮或者打包時變?yōu)楹瘮?shù)。
首先我們要了解一般情況下什么是函數(shù)聲明語句,什么是函數(shù)表達式語句,以便于接下來的實驗。
辨別方法:以“function”開頭的有名稱的函數(shù)是函數(shù)聲明語句。
function a();//函數(shù)聲明語句
var a = function();//函數(shù)表達式語句
下面我們在分析一道面試題:
var a = function(){}
var b = function(){}
console.log(a()+b());//輸出結(jié)果是NaN
因為解釋器會把前面的a()認(rèn)為是一個語句塊的結(jié)束,后面的‘+’一元運算符有把后面b()轉(zhuǎn)換為數(shù)字這么一個功能,所以得到的結(jié)果是NaN。
因此我們在做自執(zhí)行函數(shù)的時候,要把函數(shù)的聲明變?yōu)楹瘮?shù)表達式,這樣就不會影響輸出的結(jié)果了。
方法1:
(function(){
})();
方法2:
(function(){
}() );
方法3(通過操作符):但是這種方法仍然會占用命名空間,所以不建議使用。
var a = function (){
console.log(2)
}()
方法4(通過操作符)與或操作符:
false || function (){
console.log(2)
}()
true && function (){
console.log(2)
}()
0 , function (){
console.log(2)
}()
注:通過操作符實現(xiàn)自執(zhí)行函數(shù)一般使用在打包工具里面,比如webpack打包后會經(jīng)??吹?” 0,functtion(){}()“
方法5:(一元運算符)一元運算符仍然可以將函數(shù)聲明轉(zhuǎn)換為函數(shù)表達式,在bootstrap框架中常用。
! function (){
console.log(2)
}()
-function (){
console.log(2)
}()
+function (){
console.log(2)
}()
方法6:new一個匿名函數(shù),后面可省略括號。(不建議使用,會產(chǎn)生爭議)
new function (){
console.log(2)
};//在不傳參的情況下使用new也可以自執(zhí)行,可以去掉小括號,不常用。
以上方法性能比較:
除了一元運算符的時候性能偏低,因為要進行一次數(shù)字類型的轉(zhuǎn)換,其他的都可以。
應(yīng)用:
我們要了解,為什么使用自執(zhí)行函數(shù),確切的說是自執(zhí)行函數(shù)的優(yōu)點以及缺點:
1.避免作用域命名污染
2.提升性能(減少了對作用域的查找)
3.避免全局命名沖突
比如jq里面暴露給全局作用域$和query兩個變量,為了解決這個問題,我們可以將window.jq作為一個實參傳遞給一個立即執(zhí)行的匿名函數(shù)。這樣的話,我們再次命名$或者query就不會有沖突了。
4.有利于代碼壓縮(可以用簡單字符串代替)
5.保存閉包狀態(tài)
6.顛倒代碼執(zhí)行順序
(function(){})(bb())
console.log(12)
function bb(){
console.log(22)
};//打印順序是22,12
這就叫做UMD通用模塊規(guī)范,在實際開發(fā)過程中被廣泛應(yīng)用。
7.模仿塊級作用域
作用域的內(nèi)部可以訪問到外部,外部不可以訪問到內(nèi)部,js作用域的缺陷就是沒有塊級作用域。
比如:
for (var i = 0; i <6; i++) {
}
console.log(i);//打印出來的是6,在for循環(huán)外面仍然可以訪問到變量i。
三個特殊的語句可以欺騙語法分析:
evel(); //內(nèi)部存放js代碼可被執(zhí)行
with(object instance) { //代碼塊 } ; // with 語句可以方便地用來引用某個特定對象中已有的屬性,但是不能用來給對象添加屬性。要給對象創(chuàng)建新的屬性,必須明確地引用該對象。
try { // 此處是可能產(chǎn)生例外的語句 } catch(error) { // 此處是負(fù)責(zé)例外處理的語句 } finally { // 此處是出口語句 }
所以在ES3下,嚴(yán)格來說js是沒有塊級作用域的,但是以上三種方法可以實現(xiàn)塊級作用域的效果。
常用的有try catch,把要聲明的變量放在try里面,然后當(dāng)一個錯誤拋出,讓cath接住使用。缺點:1.多個塊級作用域需要多個嵌套;2.性能問題。
匿名自執(zhí)行函數(shù)只能模擬塊級作用域,并非真正的作用域。
let定義的作用域是塊級作用域,但不要輕易使用,針對開發(fā)場景來選擇。
8.填坑(加載第三方插件時候的一些問題)
比如有個人寫了這樣一段代碼:undefined=true,再早之前undefined是可以被賦值的,所以這段代碼不會報錯,但是這樣會致使你下面的一些判斷出錯
這時候如果使用匿名自執(zhí)行函數(shù)就可以解決:
(function(undefined){
console.log(undefined)
}())