摘要:而閉包的妙處在于,當函數(shù)在執(zhí)行完畢后它的活動對象不會被銷毀,因為匿名函數(shù)的作用域鏈仍然在引用函數(shù)的活動對象它的作用域鏈會被銷毀。
一、閉包
閉包是指有權訪問另一個函數(shù)作用域中的變量的函數(shù)。
創(chuàng)建閉包的常用方式是,在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。
請看以下代碼:我們在createComparisonFunction函數(shù)里創(chuàng)建了一個閉包
function createComparisonFunction(propertyName) { return function(obj1, obj2) { var val1 = obj1[propertyName]; var val2 = obj2[propertyName]; if (val1 < val2) { //若返回負數(shù),則第一個參數(shù)位于第二個參數(shù)之前 return -1; } else if (val1 > val2) { //若返回正數(shù),則第一個參數(shù)位于第二個參數(shù)之后 return 1; } else { return 0; } }; } //創(chuàng)建函數(shù) var compareNames = createComparisonFunction("name"); //調(diào)用函數(shù) var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
當某個函數(shù)第一次被調(diào)用時,會創(chuàng)建一個執(zhí)行環(huán)境(execution context)和相應的作用域鏈,并把作用域鏈賦值給一個特殊的內(nèi)部屬性([[Scope]])。然后,使用this、arguments和其他命名參數(shù)的值來初始化函數(shù)的活動對象(activation object)。但在作用域鏈中,外部函數(shù)的活動對象始終位于第二位,外部函數(shù)的外部函數(shù)的活動對象處于第三位,……直至作為作用域鏈終點的全局執(zhí)行環(huán)境。
講這么多,其實就是下面這幅圖:
普通函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀。
而閉包的妙處在于,當createComparisonFunction()函數(shù)在執(zhí)行完畢后:
它的活動對象不會被銷毀,因為匿名函數(shù)的作用域鏈仍然在引用createComparisonFunction()函數(shù)的活動對象;
它的作用域鏈會被銷毀。
當匿名函數(shù)都被銷毀之后,createComparisonFunction()函數(shù)的活動對象才會被銷毀。所以,記得要解除對匿名函數(shù)的引用,以釋放內(nèi)存。
//解除對匿名函數(shù)的引用(以便釋放內(nèi)存) compareNames = null;
對了,createComparisonFunction()函數(shù)還順便是個比較函數(shù),可用于sort。
var data = [{ name: "Zah", age:20 }, { name:"Amy", age:30 }]; data.sort(createComparisonFunction("name")); //data: //0: Object { name: "Amy", age: 30 } //1: Object { name: "Zah", age: 20 } data.sort(createComparisonFunction("age")); //data: //0: Object { name: "Zah", age: 20 } //1: Object { name: "Amy", age: 30 }二、閉包中的this
this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:
在全局函數(shù)中,this等于window
當函數(shù)作為某個對象的方法調(diào)用時,this等于那個對象
匿名函數(shù)的執(zhí)行環(huán)境具有全局性,this通常等于window
請看以下代碼:
var name = "The Window"; var obj = { name: "My Obj", getNameFunc: function() { return function() { return this.name; }; } }; alert(obj.getNameFunc()()); //"The Window"(非嚴格模式下)
為啥不是"My Obj"?說好的閉包能訪問到外部作用域的變量值呢?
對,這話是沒錯的。但是,return的這個匿名函數(shù),沒有被修改過this,它的this對象依然指向window。當沿著作用域鏈搜索this值的時候,先搜索到了自己的活動對象的this值,便停止搜索,自然而然this等于window了。
講人話就是:先吃自己碗里的this。
那我就是想吃別人碗里的this怎么辦?(傲嬌.jpg)
var name = "The Window"; var obj = { name: "My Obj", getNameFunc: function() { var that = this; //加一個變量that引用obj return function() { return that.name; }; } }; alert(obj.getNameFunc()()); //"My Obj"三、模仿塊級作用域
我們一定遇到過這個問題:
用setTimeOut輸出1-10,一秒一個
最簡單的方法當然是:
for (let i = 0; i < 10; i++) { setTimeout(function() { alert(i); }, 1000*i); }
那我偏要用閉包呢:
for (var i = 0; i < 10; i++) { (function(i) { setTimeout(function() { alert(i); }, 1000*i) })(i) }
每次循環(huán)中,立即執(zhí)行匿名函數(shù),并傳入一個參數(shù)i。由于函數(shù)參數(shù)是按值傳遞的,所以就會把變量i的當前值復制給參數(shù)i,從而輸出預期的i值。
而這個就是我們手動模仿出來的塊級作用域(私有作用域):
(function() { // 塊級作用域 })()
將函數(shù)聲明包含在一對圓括號中,代表它是一個函數(shù)表達式。緊隨其后的圓括號會立即調(diào)用這個函數(shù)。因為JavaScript將function關鍵字當作一個函數(shù)聲明的開始,函數(shù)聲明后面不能跟圓括號,而函數(shù)表達式可以跟圓括號。
未完待續(xù)~若有不足,請多指教,不勝感激!
以上代碼借鑒于《Javascript高級程序設計》
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104051.html
摘要:深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對閉包的定義為閉包是指那些能夠訪問自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對閉包的定義為: 閉包是指那些能夠訪問自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...
摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內(nèi)部函數(shù)的最后一個值,這引起的一個副作用就是如果內(nèi)部函數(shù)在一個循環(huán)中,那么變量的值始終為最后一個值。 (關注福利,關注本公眾號回復[資料]領取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:為了更好的理解,在閱讀此文之前建議先閱讀上一篇進擊之詞法作用域與作用域鏈什么是閉包閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。在中函數(shù)構成閉包。 為了更好的理解,在閱讀此文之前建議先閱讀上一篇《進擊JavaScript之詞法作用域與作用域鏈》 1.什么是閉包 閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。所謂的閉包就是...
摘要:當面試中讓我解釋一下閉包時我懵逼了。這個解釋開始可能有點晦澀,讓我們抽絲剝繭摘下閉包的真面目。此文不詳述作用域有專門的主題闡述,不過作用域是理解閉包原理的基礎。這才是閉包的真正便利之處。閉包使用不當就會很坑。 原文鏈接 為什么深度學習JavaScript? JavaScript如今是最流行的編程語言之一。它運行在瀏覽器、服務器、移動設備、桌面應用,也可能包括冰箱。無需我舉其他再多不相干...
摘要:閉包確實是一個說爛了的概念,校招社招都會被問到,今天總結一番。先下定義,閉包是函數(shù)和該函數(shù)的詞法作用域的組合。在這個栗子里,函數(shù)以及它對變量的引用就構成了閉包。閉包和作用域?qū)τ陂]包和作用域的關系,我的理解是閉包其實就是作用域的延伸。 閉包確實是一個說爛了的概念,校招社招都會被問到,今天總結一番。先下定義,閉包是函數(shù)和該函數(shù)的詞法作用域的組合。其實這個定義是比較教條的,可以直白的理解為閉...
閱讀 855·2021-11-15 17:58
閱讀 3658·2021-11-12 10:36
閱讀 3794·2021-09-22 16:06
閱讀 969·2021-09-10 10:50
閱讀 1333·2019-08-30 11:19
閱讀 3317·2019-08-29 16:26
閱讀 942·2019-08-29 10:55
閱讀 3349·2019-08-26 13:48