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