????JS自執(zhí)行函數(shù)又稱為IIFE魏烫,在我們開發(fā)過程中會(huì)使用到大量的自執(zhí)行函數(shù)骡尽。
IIFE寫法:
????使用建議:在使用只執(zhí)行函數(shù)前面加上 “ ; ”患亿,避免壓縮或者打包時(shí)變?yōu)楹瘮?shù)慌核。
? ? 首先我們要了解一般情況下什么是函數(shù)聲明語句商乎,什么是函數(shù)表達(dá)式語句央拖,以便于接下來的實(shí)驗(yàn)。
????辨別方法:以“function”開頭的有名稱的函數(shù)是函數(shù)聲明語句鹉戚。
function a();//函數(shù)聲明語句
var a = function();//函數(shù)表達(dá)式語句
? ? 下面我們?cè)诜治鲆坏烂嬖囶}:
var a = function(){}
var b = function(){}
console.log(a()+b());//輸出結(jié)果是NaN
因?yàn)榻忉屍鲿?huì)把前面的a()認(rèn)為是一個(gè)語句塊的結(jié)束鲜戒,后面的‘+’一元運(yùn)算符有把后面b()轉(zhuǎn)換為數(shù)字這么一個(gè)功能,所以得到的結(jié)果是NaN抹凳。
因此我們?cè)谧鲎詧?zhí)行函數(shù)的時(shí)候遏餐,要把函數(shù)的聲明變?yōu)楹瘮?shù)表達(dá)式,這樣就不會(huì)影響輸出的結(jié)果了赢底。
方法1:
(function(){
})();
方法2:
(function(){
}() );
方法3(通過操作符):但是這種方法仍然會(huì)占用命名空間失都,所以不建議使用。
var a = function (){
console.log(2)
}()
方法4(通過操作符)與或操作符:
false || function (){
console.log(2)
}()
true && function (){
console.log(2)
}()
0 , function (){
console.log(2)
}()
注:通過操作符實(shí)現(xiàn)自執(zhí)行函數(shù)一般使用在打包工具里面颖系,比如webpack打包后會(huì)經(jīng)承崞剩看到 ” 0,functtion(){}()“
方法5:(一元運(yùn)算符)一元運(yùn)算符仍然可以將函數(shù)聲明轉(zhuǎn)換為函數(shù)表達(dá)式,在bootstrap框架中常用嘁扼。
! function (){
console.log(2)
}()
-function (){
console.log(2)
}()
+function (){
console.log(2)
}()
方法6:new一個(gè)匿名函數(shù)信粮,后面可省略括號(hào)。(不建議使用趁啸,會(huì)產(chǎn)生爭議)
new function (){
console.log(2)
};//在不傳參的情況下使用new也可以自執(zhí)行强缘,可以去掉小括號(hào),不常用不傅。
以上方法性能比較:
除了一元運(yùn)算符的時(shí)候性能偏低旅掂,因?yàn)橐M(jìn)行一次數(shù)字類型的轉(zhuǎn)換,其他的都可以访娶。
應(yīng)用:
我們要了解商虐,為什么使用自執(zhí)行函數(shù),確切的說是自執(zhí)行函數(shù)的優(yōu)點(diǎn)以及缺點(diǎn):
? ? ? ? 1.避免作用域命名污染
? ? ? ? 2.提升性能(減少了對(duì)作用域的查找)
? ? ? ? 3.避免全局命名沖突
????????????????比如jq里面暴露給全局作用域$和query兩個(gè)變量,為了解決這個(gè)問題秘车,我們可以將window.jq作為一個(gè)實(shí)參傳遞給一個(gè)立即執(zhí)行的匿名函數(shù)典勇。這樣的話,我們?cè)俅蚊?或者query就不會(huì)有沖突了叮趴。
? ? ? ? 4.有利于代碼壓縮(可以用簡單字符串代替)
? ? ? ? 5.保存閉包狀態(tài)
? ? ? ? 6.顛倒代碼執(zhí)行順序
(function(){})(bb())
console.log(12)
function bb(){
????????console.log(22)
}割笙;//打印順序是22,12
這就叫做UMD通用模塊規(guī)范眯亦,在實(shí)際開發(fā)過程中被廣泛應(yīng)用伤溉。
? ? ? ? 7.模仿塊級(jí)作用域
????作用域的內(nèi)部可以訪問到外部,外部不可以訪問到內(nèi)部妻率,js作用域的缺陷就是沒有塊級(jí)作用域乱顾。
? ? 比如:
????????????for (var i = 0; i <6; i++) {
????????????}
????????????console.log(i);//打印出來的是6,在for循環(huán)外面仍然可以訪問到變量i宫静。
三個(gè)特殊的語句可以欺騙語法分析:
? ??????evel(); //內(nèi)部存放js代碼可被執(zhí)行
? ??????with(object?instance)?? {?? ????????//代碼塊?? }? 糯耍; // with?語句可以方便地用來引用某個(gè)特定對(duì)象中已有的屬性,但是不能用來給對(duì)象添加屬性囊嘉。要給對(duì)象創(chuàng)建新的屬性,必須明確地引用該對(duì)象革为。
? ??????try { // 此處是可能產(chǎn)生例外的語句 } catch(error) { // 此處是負(fù)責(zé)例外處理的語句 } finally { // 此處是出口語句 }
所以在ES3下扭粱,嚴(yán)格來說js是沒有塊級(jí)作用域的,但是以上三種方法可以實(shí)現(xiàn)塊級(jí)作用域的效果震檩。
常用的有try catch琢蛤,把要聲明的變量放在try里面,然后當(dāng)一個(gè)錯(cuò)誤拋出抛虏,讓cath接住使用博其。缺點(diǎn):1.多個(gè)塊級(jí)作用域需要多個(gè)嵌套;2.性能問題迂猴。
匿名自執(zhí)行函數(shù)只能模擬塊級(jí)作用域慕淡,并非真正的作用域。
? ?let定義的作用域是塊級(jí)作用域沸毁,但不要輕易使用峰髓,針對(duì)開發(fā)場景來選擇。
? ? ? ? 8.填坑(加載第三方插件時(shí)候的一些問題)
????????????????比如有個(gè)人寫了這樣一段代碼:undefined=true息尺,再早之前undefined是可以被賦值的携兵,所以這段代碼不會(huì)報(bào)錯(cuò),但是這樣會(huì)致使你下面的一些判斷出錯(cuò)
????????????????這時(shí)候如果使用匿名自執(zhí)行函數(shù)就可以解決:
(function(undefined){
????????console.log(undefined)
}())
了解他的優(yōu)點(diǎn)之后我們才可以在正確的場景使用IIFE搂誉。