摘要:在此例中,在匿名函數被返回后,它的作用域鏈初始化為包含函數的活動對象和全局變量對象。函數在執(zhí)行完畢后,其活動對象也不會被銷毀,因為匿名函數的作用域鏈仍然在引用這個活動對象,結果就是只是的執(zhí)行環(huán)境的作用域鏈會被銷毀,其活動對象會留在內存中。
寫在前面
注:這個系列是本人對js知識的一些梳理,其中不少內容來自書籍:Javascript高級程序設計第三版和JavaScript權威指南第六版,感謝它們的作者和譯者。有發(fā)現(xiàn)什么問題的,歡迎留言指出。
1.執(zhí)行環(huán)境執(zhí)行環(huán)境簡稱“環(huán)境”,定義了變量或函數有權訪問的其他數據。每個執(zhí)行環(huán)境都有一個與之關聯(lián)的變量對象,環(huán)境中定義的所有變量和函數都保存在這個對象中。
全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境。在Web瀏覽器中,全局執(zhí)行環(huán)境被認為是window對象,因此所有全局變量和函數都是作為window對象的屬性和方法創(chuàng)建的。
某個執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢,環(huán)境被銷毀,保存在其中的所有變量和函數定義也隨之銷毀。
執(zhí)行流:每個函數都有自己的執(zhí)行環(huán)境,當執(zhí)行流進入一個函數時,函數的環(huán)境就會被推入一個環(huán)境棧中。而在函數執(zhí)行之后,棧將其環(huán)境彈出,把控制權返回給之前的執(zhí)行環(huán)境。
代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈(scope chain),用途是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數,則將其活動對象作為變量對象?;顒訉ο笤谧铋_始時只包含arguments 對象。作用域鏈的下一個變量對象來自包含環(huán)境,而再下一個變量對象則來自下一個包含環(huán)境。這樣,一直延續(xù)到全局執(zhí)行環(huán)境;全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象:
var color = "blue"; function changeColor() { if(color == "blue"){ color = "red"; }else{ color = "blue"; } } changeColor(); console.log("color is:" + color);//red
例子中,函數changeColor()的作用域鏈包含兩個對象:它自己的變量對象(其中定義著arguments對象)和全局環(huán)境的變量對象??梢栽诤瘮祪炔吭L問變量 color,就是因為可以在作用域鏈中找到它。
var color = "blue"; function changeColor() { var anotherColor = "red"; function swapColors() { var tempColor = anotherColor; anotherColor = color; color = tempColor; //這里可以訪問color、anotherColor和tempColor } //這里可以訪問color和anotherColor,但不能訪問tempColor swapColors(); } // 這里只能訪問color changeColor();
以上共涉及3個執(zhí)行環(huán)境:全局環(huán)境、changeColor()的局部環(huán)境和swapColors()的局部環(huán)境。顯然,內部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境不能訪問內部環(huán)境中的任何變量和函數。
2.閉包閉包是指有權訪問另一個函數作用域中的變量的函數。創(chuàng)建閉包的常見方式,就是在一個函數內部創(chuàng)建另一個函數。
function createComparisonFunction(propertyName) { return function (object1, object2) { var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1value2){ return 1; }else{ return 0; } } } //創(chuàng)建函數 var compareNames = createComparisonFunction("name"); //調用函數 var result = compareNames({name:"jaychou"},{name:"xiaoming"}); //解除對匿名函數的引用(釋放內存) compareNames = null;
以上過程:
1.定義函數內部的函數時,會將它的包含函數的活動對象添加到它的作用域鏈中。在此例中,在匿名函數被返回后,它的作用域鏈初始化為包含createComparisonFunction()函數的活動對象和全局變量對象。
2.createComparisonFunction()函數在執(zhí)行完畢后,其活動對象也不會被銷毀,因為匿名函數的作用域鏈仍然在引用這個活動對象,結果就是只是createComparisonFunction()的執(zhí)行環(huán)境的作用域鏈會被銷毀,其活動對象會留在內存中。
3.直到代碼中將匿名函數置為null釋放內存后,createComparisonFunction()的活動對象才會被銷毀。
注意:由于閉包會攜帶包含它的函數的作用域,所以會比其他函數占用更多的內存,過多使用閉包會導致內存占用過多,所以在很有必要時才考慮使用閉包。
3.閉包的最常見問題function createFunctions() { var result = new Array(); for(var i=0;i<10;i++){ result[i] = function () { return i; }; } return result; } console.log(createFunctions()[4]());//會打印10
數組里面的每個函數都是打印10,因為每個函數的作用域鏈中都保存著createFunctions()函數的活動對象,所以他們引用的都是同一個變量i。當函數數組被返回時,變量i的值是10,所以就是上面的結果了。通過創(chuàng)建另一個匿名函數的改造如下符合預期:
function createFunctions() { var result = new Array(); for(var i=0;i<10;i++){ result[i] = function (num) { return function () { return num; } }(i); } return result; } console.log(createFunctions()[4]());//會打印4
沒有直接把閉包賦值給數組,而是定義了一個匿名函數,并將立即執(zhí)行該匿名函數的結果賦給函數,函數參數是按值傳遞的,所以會把變量i的當前值復制給參數num。
在這個立即執(zhí)行函數里面創(chuàng)建并返回了一個訪問num的閉包。這個閉包被返回時都準確包含了對應的包含環(huán)境的活動對象的num值。
4.閉包的常見作用給構造函數創(chuàng)建私用變量和私有函數,并定義特權方法;
創(chuàng)建單例,在函數最后返回公用方法
等等
總體而言,閉包對于我們理解執(zhí)行環(huán)境,理解作用域鏈很有幫助,但平常如果不是很有必要就不要用,占用內存比較多。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/108379.html
摘要:好程序員前端培訓入門之基礎知識梳理匯總,前端工程師是當前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。作用域鏈的前端,始終是當前執(zhí)行代碼所在環(huán)境的變量對象。 好程序員Web前端培訓入門之JS基礎知識梳理匯總,Web前端工程師是當前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。不論是專業(yè)還是非專業(yè),有基礎亦或是無基礎,都想通過學習Web前端實現(xiàn)高薪就業(yè)。不過,學習要一...
摘要:好程序員前端培訓入門之基礎知識梳理匯總,前端工程師是當前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。作用域鏈的前端,始終是當前執(zhí)行代碼所在環(huán)境的變量對象。 好程序員Web前端培訓入門之JS基礎知識梳理匯總,Web前端工程師是當前各大企業(yè)都比較稀缺的人才,薪資待遇和就業(yè)前景都很不錯。不論是專業(yè)還是非專業(yè),有基礎亦或是無基礎,都想通過學習Web前端實現(xiàn)高薪就業(yè)。不過,學習要一...
摘要:引言滿滿的干貨,面試必系列,參考大量資料,并集合自己的理解以及相關的面試題,對核心知識點中的作用域閉包上下文進行了梳理。如果在小區(qū)這個作用域找到了張老師,我就會在張老師的輔導下學鋼琴我張老師房間鋼琴構成了學琴的上下文環(huán)境。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 滿滿的干貨,面試必bei系列,參考大...
摘要:前言這段時間一直在消化作用域鏈和閉包的相關知識。而作用域鏈則是這套規(guī)則這套規(guī)則的具體運行。是變量對象的縮寫那這樣放有什么好處呢我們知道作用域鏈保證了當前執(zhí)行環(huán)境對符合訪問權限的變量和函數的有序訪問。 前言:這段時間一直在消化作用域鏈和閉包的相關知識。之前看《JS高程》和一些技術博客,對于這些概念的論述多多少少不太清楚或者不太完整,包括一些大神的技術文章。這也給我的學習上造成了一些困惑,...
閱讀 2766·2021-10-12 10:12
閱讀 842·2019-08-29 17:25
閱讀 2855·2019-08-29 17:24
閱讀 3325·2019-08-29 17:19
閱讀 1865·2019-08-29 15:39
閱讀 3140·2019-08-26 16:50
閱讀 2042·2019-08-26 12:17
閱讀 2766·2019-08-26 12:16