摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問(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天。
本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃,點(diǎn)擊查看前端進(jìn)階的破冰之旅
如果覺(jué)得本系列不錯(cuò),歡迎轉(zhuǎn)發(fā),您的支持就是我堅(jiān)持的最大動(dòng)力。
本期推薦文章從作用域鏈談閉包 ,由于微信不能訪問(wèn)外鏈,點(diǎn)擊閱讀原文就可以啦。
推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包??赐瓯疚膶?duì)于相關(guān)知識(shí)的邏輯會(huì)清晰很多。
閱讀筆記紅寶書(shū)(p178)上對(duì)于閉包的定義:閉包是指有權(quán)訪問(wèn)另外一個(gè)函數(shù)作用域中的變量的函數(shù)
關(guān)鍵在于下面兩點(diǎn):
是一個(gè)函數(shù)
能訪問(wèn)另外一個(gè)函數(shù)作用域中的變量
對(duì)于閉包有下面三個(gè)特性:
1、閉包可以訪問(wèn)當(dāng)前函數(shù)以外的變量
function getOuter(){ var date = "815"; function getDate(str){ console.log(str + date); //訪問(wèn)外部的date } return getDate("今天是:"); //"今天是:815" } getOuter();
2、即使外部函數(shù)已經(jīng)返回,閉包仍能訪問(wèn)外部函數(shù)定義的變量
function getOuter(){ var date = "815"; function getDate(str){ console.log(str + date); //訪問(wèn)外部的date } return getDate; //外部函數(shù)返回 } var today = getOuter(); today("今天是:"); //"今天是:815" today("明天不是:"); //"明天不是:815"
3、閉包可以更新外部變量的值
function updateCount(){ var count = 0; function getCount(val){ count = val; console.log(count); } return getCount; //外部函數(shù)返回 } var count = updateCount(); count(815); //815 count(816); //816作用域鏈
Javascript中有一個(gè)執(zhí)行上下文(execution context)的概念,它定義了變量或函數(shù)有權(quán)訪問(wèn)的其它數(shù)據(jù),決定了他們各自的行為。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。
詳情查看 【進(jìn)階1-2期】JavaScript深入之執(zhí)行上下文棧和變量對(duì)象
作用域鏈:當(dāng)訪問(wèn)一個(gè)變量時(shí),解釋器會(huì)首先在當(dāng)前作用域查找標(biāo)示符,如果沒(méi)有找到,就去父作用域找,直到找到該變量的標(biāo)示符或者不在父作用域中,這就是作用域鏈。
作用域鏈和原型繼承查找時(shí)的區(qū)別:如果去查找一個(gè)普通對(duì)象的屬性,但是在當(dāng)前對(duì)象和其原型中都找不到時(shí),會(huì)返回undefined;但查找的屬性在作用域鏈中不存在的話就會(huì)拋出ReferenceError。
作用域鏈的頂端是全局對(duì)象,在全局環(huán)境中定義的變量就會(huì)綁定到全局對(duì)象中。
全局環(huán)境// my_script.js "use strict"; var foo = 1; var bar = 2; function myFunc() { var a = 1; var b = 2; var foo = 3; console.log("inside myFunc"); } console.log("outside"); myFunc();
定義時(shí):當(dāng)myFunc被定義的時(shí)候,myFunc的標(biāo)識(shí)符(identifier)就被加到了全局對(duì)象中,這個(gè)標(biāo)識(shí)符所引用的是一個(gè)函數(shù)對(duì)象(myFunc function object)。
內(nèi)部屬性[[scope]]指向當(dāng)前的作用域?qū)ο?,也就是函?shù)的標(biāo)識(shí)符被創(chuàng)建的時(shí)候,我們所能夠直接訪問(wèn)的那個(gè)作用域?qū)ο螅慈謱?duì)象)。
myFunc所引用的函數(shù)對(duì)象,其本身不僅僅含有函數(shù)的代碼,并且還含有指向其被創(chuàng)建的時(shí)候的作用域?qū)ο蟆?/p>
調(diào)用時(shí):當(dāng)myFunc函數(shù)被調(diào)用的時(shí)候,一個(gè)新的作用域?qū)ο蟊粍?chuàng)建了。新的作用域?qū)ο笾邪琺yFunc函數(shù)所定義的本地變量,以及其參數(shù)(arguments)。這個(gè)新的作用域?qū)ο蟮母缸饔糜驅(qū)ο缶褪窃谶\(yùn)行myFunc時(shí)能直接訪問(wèn)的那個(gè)作用域?qū)ο螅慈謱?duì)象)。
當(dāng)函數(shù)返回沒(méi)有被引用的時(shí)候,就會(huì)被垃圾回收器回收。但是對(duì)于閉包,即使外部函數(shù)返回了,函數(shù)對(duì)象仍會(huì)引用它被創(chuàng)建時(shí)的作用域?qū)ο蟆?/p>
"use strict"; function createCounter(initial) { var counter = initial; function increment(value) { counter += value; } function get() { return counter; } return { increment: increment, get: get }; } var myCounter = createCounter(100); console.log(myCounter.get()); // 返回 100 myCounter.increment(5); console.log(myCounter.get()); // 返回 105
當(dāng)調(diào)用 createCounter(100) 時(shí),內(nèi)嵌函數(shù)increment和get都有指向createCounter(100) scope的引用。假設(shè)createCounter(100)沒(méi)有任何返回值,那么createCounter(100) scope不再被引用,于是就可以被垃圾回收。
但是createCounter(100)實(shí)際上是有返回值的,并且返回值被存儲(chǔ)在了myCounter中,所以對(duì)象之間的引用關(guān)系如下圖:
即使createCounter(100)已經(jīng)返回,但是其作用域仍在,并且只能被內(nèi)聯(lián)函數(shù)訪問(wèn)??梢酝ㄟ^(guò)調(diào)用myCounter.increment() 或 myCounter.get()來(lái)直接訪問(wèn)createCounter(100)的作用域。
當(dāng)myCounter.increment() 或 myCounter.get()被調(diào)用時(shí),新的作用域?qū)ο髸?huì)被創(chuàng)建,并且該作用域?qū)ο蟮母缸饔糜驅(qū)ο髸?huì)是當(dāng)前可以直接訪問(wèn)的作用域?qū)ο蟆?/p>
調(diào)用get()時(shí),當(dāng)執(zhí)行到return counter時(shí),在get()所在的作用域并沒(méi)有找到對(duì)應(yīng)的標(biāo)示符,就會(huì)沿著作用域鏈往上找,直到找到變量counter,然后返回該變量。
多帶帶調(diào)用increment(5)時(shí),參數(shù)value保存在當(dāng)前的作用域?qū)ο?。?dāng)函數(shù)要訪問(wèn)counter時(shí),沒(méi)有找到,于是沿著作用域鏈向上查找,在createCounter(100)的作用域找到了對(duì)應(yīng)的標(biāo)示符,increment()就會(huì)修改counter的值。除此之外,沒(méi)有其他方式來(lái)修改這個(gè)變量。閉包的強(qiáng)大也在于此,能夠存貯私有數(shù)據(jù)。
創(chuàng)建兩個(gè)函數(shù):myCounter1和myCounter2
//my_script.js "use strict"; function createCounter(initial) { /* ... see the code from previous example ... */ } //-- create counter objects var myCounter1 = createCounter(100); var myCounter2 = createCounter(200);
關(guān)系圖如下
myCounter1.increment和myCounter2.increment的函數(shù)對(duì)象擁有著一樣的代碼以及一樣的屬性值(name,length等等),但是它們的[[scope]]指向的是不一樣的作用域?qū)ο蟆?/p> 參考
從作用域鏈談閉包往期文章查看
【進(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ì)劃安排每周面試重難點(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://systransis.cn/yun/99551.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ì)...
摘要:閉包面試題解由于作用域鏈機(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)階期理解中的執(zhí)行上下文和執(zhí)行棧進(jìn)階期深入之執(zhí)行上下文棧和變量對(duì)象但是今天補(bǔ)充一個(gè)知識(shí)點(diǎn)某些情況下,調(diào)用堆棧中函數(shù)調(diào)用的數(shù)量超出了調(diào)用堆棧的實(shí)際大小,瀏覽器會(huì)拋出一個(gè)錯(cuò)誤終止運(yùn)行。 (關(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)用堆棧,今天是第3天。 本計(jì)劃一共28期,每期重點(diǎn)攻...
摘要:引擎對(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ì)劃...
摘要:本期推薦文章類內(nèi)存泄漏及如何避免,由于微信不能訪問(wèn)外鏈,點(diǎn)擊閱讀原文就可以啦。四種常見(jiàn)的內(nèi)存泄漏劃重點(diǎn)這是個(gè)考點(diǎn)意外的全局變量未定義的變量會(huì)在全局對(duì)象創(chuàng)建一個(gè)新變量,如下。因?yàn)槔习姹镜氖菬o(wú)法檢測(cè)節(jié)點(diǎn)與代碼之間的循環(huán)引用,會(huì)導(dǎo)致內(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)階的第一期,本周的主題...
閱讀 1801·2021-11-11 16:55
閱讀 2611·2021-08-27 13:11
閱讀 3661·2019-08-30 15:53
閱讀 2328·2019-08-30 15:44
閱讀 1421·2019-08-30 11:20
閱讀 1064·2019-08-30 10:55
閱讀 967·2019-08-29 18:40
閱讀 3067·2019-08-29 16:13