JS中立即執行函數和閉包的區別


函數聲明
規則:必須指定一個函數名字

foo();
function foo() {
console.log("函數聲明")
}

由於函數聲明會被提升,所以調用函數可以在之前或之后調用

 

函數表達式
規則:將函數賦值給一個變量

var foo = function () {
console.log("函數表達式")
}
foo()

由於函數表達式,只會對變量foo進行提升,只有運行到代碼處,才會對變量foo進行賦值,所以調用函數必須在函數表達式之后

 

立即執行函數
常用的兩種方式

(function () {
console.log("立即執行函數")
})();

(function () {
console.log("立即執行函數")
}())

 

立即執行函數的演變
1:在函數表達式后加括號,可以立即執行函數

var foo = function () {
console.log("立即執行函數")
}();

2:在匿名函數后加括號,不可以立即執行函數

function () {
console.log("立即執行函數")
}();

在函數表達式后加括號可以立即執行函數,但如果不把匿名函數賦值給變量,而直接在后邊加一個括號,則會報語法錯誤。因為當JS引擎在遇到function時,會默認把它當作是函數聲明,所以必須要有一個函數名

3:在函數聲明后加括號,不可以立即執行函數

function foo() {
console.log("立即執行函數")
}()

如果給匿名函數添加一個函數名,也就變成了函數聲明,然后在函數聲明后加括號,也會報語法錯誤,因為函數聲明會被提升,當提升后就相當於在代碼中只寫了一對括號,而這個括號和前面的函數聲明又沒什么關系,所以語法報錯

javascript中,括號內不允許包含語句,但可以是表達式
引擎先遇到括號,然后遇到關鍵字function , 就自動把括號里面的代碼識別為函數表達式,而不是函數聲明,所以立即執行函數可以這樣寫(function(){})()

 

閉包
定義:內部函數被外部函數以外的變量引用時,就形成了一個閉包
常用方式示例:

function foo() {
    var num = 10;
    return function () {
    var age= 20;
    console.log(++num);
    console.log(++age);
    }
}
var f = foo();
f(); //11 21
f(); //12 21

通過閉包就可以讓外部作用域訪問函數內部作用域的變量,我們知道當函數執行完以后,會立即銷毀,但 foo 函數內的 num 屬性被內部的匿名函數引用着,而內部函數又被外部變量 f 引用着,所以函數 foo 在執行完以后雖然會立即銷毀,但它內部的匿名函數在創建的時候就會隨之創建一個特殊的容器,用於保存 上層作用域 中 變量 的引用,所以foo 函數中的 num 並不會銷毀,當執行第一次 f() 時,會創建 f() 對應的作用域,其中num 會從之前創建的特殊的容器中取出上層作用域中變量的值,而 age 會立即聲明一個,當函數執行完畢后,就會銷毀對應的作用域,此時 age 也會隨之銷毀,但變量 f 對應的指針地址不會變,當再次執行 f() 時,又會再創建一個 f() 對應的作用域,num 還是會從上層作用域中拿,但 age 還是會重新聲明,使用完后還是會被銷毀。
很顯然這樣會一直持有對 num 的引用,無法進行回收,造成內存占用,所以當不使用時,可以把 f 置為null,來讓垃圾回收器進行回收。

在Javascript中,如果一個對象不再被引用,那么這個對象就會被GC回收。
如果兩個對象互相引用,而不再被第3者所引用,那么這兩個互相引用的對象也
會被回收。因為函數a被b引用,b又被a外的c引用,這就是為什么函數a執行后
不會被回收的原因


閉包優點和缺點

優點

減少全局變量的使用,保證了內部變量的安全,同時外部函數也可以訪問內部函數的變量
在內存中維持一個變量,也可以用作緩存
缺點

被引用的內部變量不能被銷毀,增大了內存消耗,使用不當易造成內存泄露,解決辦法可以在內部變量不使用時,把外部的引用置為 null
閉包就是函數間的跨作用域訪問,會導致性能損失
立即執行函數和閉包的區別
立即執行函數和閉包沒有關系,雖然兩者會經常結合在一起使用,但兩者有本質的不同

立即執行函數只是函數的一種調用方式,只是聲明完之后立即執行,這類函數一般都只是調用一次(可用於單例對象上),調用完之后會立即銷毀,不會占用內存

閉包則主要是讓外部函數可以訪問內部函數的作用域,也減少了全局變量的使用,保證了內部變量的安全,但因被引用的內部變量不能被銷毀,增大了內存消耗,使用不當易造成內存泄露

立即執行函數與閉包常結合示例

如:單例

let single = (function () {
let name = "小明";
let age = 20;
return {
getName: function () {
return name;
},
getAge: function () {
return age;
}
}
})();
console.log(single.getName()); //小明
console.log(single.getAge()); //20

給對象創建了私有變量name、age又對外提供了獲取的方法,典型的自執行函數和閉包結合使用的示例

 


原文鏈接:https://blog.csdn.net/Liu_yunzhao/article/details/90641956


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM