摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。
(關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)
本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。
本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅
如果覺得本系列不錯,歡迎轉發,您的支持就是我堅持的最大動力。
本期推薦文章深入javascript——作用域和閉包 ,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。
推薦理由本篇文章介紹了作用域、作用域鏈和閉包,然后重點介紹一個面試題的3種解法,并給出詳細解答,歡迎閱讀原文留言評論。
閱讀筆記作用域指的是一個變量和函數的作用范圍,JS中函數內聲明的所有變量在函數體內始終是可見的,在ES6前有全局作用域和局部作用域,但是沒有塊級作用域(catch只在其內部生效),局部變量的優先級高于全局變量。
作用域var scope="global"; function scopeTest(){ console.log(scope); var scope="local" } scopeTest(); //undefined
上面的代碼輸出是undefined,這是因為局部變量scope變量提升了,等效于下面
var scope="global"; function scopeTest(){ var scope; console.log(scope); scope="local" } scopeTest(); //undefined
注意,如果在局部作用域中忘記var,那么變量就被聲明為全局變量。
var data = []; for (var i = 0; i < 3; i++) { data[i] = function () { console.log(i); }; } data[0](); // 3 data[1](); // 3 data[2](); // 3
上篇文章已經介紹過了,【進階2-2期】JavaScript深入之從作用域鏈理解閉包
作用域鏈每個函數都有自己的執行上下文環境,當代碼在這個環境中執行時,會創建變量對象的作用域鏈,作用域鏈是一個對象列表或對象鏈,它保證了變量對象的有序訪問。
作用域鏈的開始是當前代碼執行環境的變量對象,常被稱之為“活躍對象”(AO),變量的查找會從第一個鏈的對象開始,如果對象中包含變量屬性,那么就停止查找,如果沒有就會繼續向上級作用域鏈查找,直到找到全局對象中
閉包function createClosure(){ var name = "jack"; return { setStr:function(){ name = "rose"; }, getStr:function(){ return name + ":hello"; } } } var builder = new createClosure(); builder.setStr(); console.log(builder.getStr()); //rose:hello
上面在函數中返回了兩個閉包,這兩個閉包都維持著對外部作用域的引用。閉包中會將外部函數的自由對象添加到自己的作用域鏈中,所以可以通過內部函數訪問外部函數的屬性,這也是javascript模擬私有變量的一種方式。
閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。
這個代碼已經貼過了,怕你們忘記,就再貼一遍
var data = []; for (var i = 0; i < 3; i++) { data[i] = function () { console.log(i); }; } data[0](); // 3 data[1](); // 3 data[2](); // 3
如果要強制返回預期的結果,怎么辦???
for (var i = 0; i < 3; i++) { (function(num) { setTimeout(function() { console.log(num); }, 1000); })(i); } // 0 // 1 // 2
var data = []; for (var i = 0; i < 3; i++) { data[i] = (function (num) { return function(){ console.log(num); } })(i); } data[0](); // 0 data[1](); // 1 data[2](); // 2
無論是立即執行函數還是返回一個匿名函數賦值,原理上都是因為變量的按值傳遞,所以會將變量i的值復制給實參num,在匿名函數的內部又創建了一個用于訪問num的匿名函數,這樣每個函數都有了一個num的副本,互不影響了。
var data = []; for (let i = 0; i < 3; i++) { data[i] = function () { console.log(i); }; } data[0](); data[1](); data[2]();
解釋下原理:
var data = [];// 創建一個數組data; // 進入第一次循環 { let i = 0; // 注意:因為使用let使得for循環為塊級作用域 // 此次 let i = 0 在這個塊級作用域中,而不是在全局環境中 data[0] = function() { console.log(i); }; }
循環時,let聲明i,所以整個塊是塊級作用域,那么data[0]這個函數就成了一個閉包。這里用{}表達并不符合語法,只是希望通過它來說明let存在時,這個for循環塊是塊級作用域,而不是全局作用域。
上面的塊級作用域,就像函數作用域一樣,函數執行完畢,其中的變量會被銷毀,但是因為這個代碼塊中存在一個閉包,閉包的作用域鏈中引用著塊級作用域,所以在閉包被調用之前,這個塊級作用域內部的變量不會被銷毀。
// 進入第二次循環 { let i = 1; // 因為 let i = 1 和上面的 let i = 0 // 在不同的作用域中,所以不會相互影響 data[1] = function(){ console.log(i); }; }
當執行data[1]()時,進入下面的執行環境。
{ let i = 1; data[1] = function(){ console.log(i); }; }
在上面這個執行環境中,它會首先尋找該執行環境中是否存在i,沒有找到,就沿著作用域鏈繼續向上到了其所在的塊作用域執行環境,找到了i = 1,于是輸出了1。
思考題代碼1:
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } var foo = checkscope(); foo();
代碼2:
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope();
上面的兩個代碼中,checkscope()執行完成后,閉包f所引用的自由變量scope會被垃圾回收嗎?為什么?
參考深入javascript——作用域和閉包往期文章查看ES6之let(理解閉包)和const命令
【進階1-1期】理解JavaScript 中的執行上下文和執行棧
【進階1-2期】JavaScript深入之執行上下文棧和變量對象
【進階1-3期】JavaScript深入之內存空間詳細圖解
【進階1-4期】JavaScript深入之帶你走進內存機制
【進階1-5期】JavaScript深入之4類常見內存泄漏及如何避免
【進階2-1期】深入淺出圖解作用域鏈和閉包
【進階2-2期】JavaScript深入之從作用域鏈理解閉包
每周計劃安排每周面試重難點計劃如下,如有修改會通知大家。每周一期,為期半年,準備明年跳槽的小伙伴們可以把本公眾號[置頂]()了。
【進階1期】 調用堆棧
【進階2期】 作用域閉包
【進階3期】 this全面解析
【進階4期】 深淺拷貝原理
【進階5期】 原型Prototype
【進階6期】 高階函數
【進階7期】 事件機制
【進階8期】 Event Loop原理
【進階9期】 Promise原理
【進階10期】Async/Await原理
【進階11期】防抖/節流原理
【進階12期】模塊化詳解
【進階13期】ES6重難點
【進階14期】計算機網絡概述
【進階15期】瀏覽器渲染原理
【進階16期】webpack配置
【進階17期】webpack原理
【進階18期】前端監控
【進階19期】跨域和安全
【進階20期】性能優化
【進階21期】VirtualDom原理
【進階22期】Diff算法
【進階23期】MVVM雙向綁定
【進階24期】Vuex原理
【進階25期】Redux原理
【進階26期】路由原理
【進階27期】VueRouter源碼解析
【進階28期】ReactRouter源碼解析
交流本人Github鏈接如下,歡迎各位Star
http://github.com/yygmind/blog
我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!
如果你想加群討論每期面試知識點,公眾號回復[加群]即可
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99549.html
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:使用指定的參數調用構造函數,并將綁定到新創建的對象。由構造函數返回的對象就是表達式的結果。情況返回以外的基本類型實例中只能訪問到構造函數中的屬性,和情況完全相反,結果相當于沒有返回值。 定義 new 運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例。 ——(來自于MDN) 舉個栗子 function Car(color) { this.color = co...
摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包。作用域鏈的頂端是全局對象,在全局環境中定義的變量就會綁定到全局對象中。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周開始前端進階的第二期,本周的主題是作用域閉包,今天是第6天。 本...
摘要:箭頭函數的尋值行為與普通變量相同,在作用域中逐級尋找。題目這次通過構造函數來創建一個對象,并執行相同的個方法。 我們知道this綁定規則一共有5種情況: 1、默認綁定(嚴格/非嚴格模式) 2、隱式綁定 3、顯式綁定 4、new綁定 5、箭頭函數綁定 其實大部分情況下可以用一句話來概括,this總是指向調用該函數的對象。 但是對于箭頭函數并不是這樣,是根據外層(函數或者全局)作用域(...
摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...
閱讀 1763·2021-10-11 10:59
閱讀 2401·2021-09-30 09:53
閱讀 1764·2021-09-22 15:28
閱讀 2795·2019-08-29 15:29
閱讀 1557·2019-08-29 13:53
閱讀 3207·2019-08-29 12:34
閱讀 2848·2019-08-26 10:16
閱讀 2660·2019-08-23 15:16