摘要:塊作用域在中沒(méi)有塊作用域也就是說(shuō)在中聲明的變量會(huì)泄露到外面作用域而中新增的可以將變量綁定到所在的任意作用域通常是內(nèi)部,換句話說(shuō),為其聲明的變量隱式的劫持了所在的塊作用域??偨Y(jié)作用域其實(shí)是有執(zhí)行上下文中的變量對(duì)象和作用域鏈共同構(gòu)成的。
執(zhí)行上下文(也稱(chēng)執(zhí)行環(huán)境)堆棧
執(zhí)行上下文是javascript最重要的一個(gè)概念,執(zhí)行上下文定義了變量或函數(shù)有權(quán)訪問(wèn)的其他數(shù)據(jù),決定了它們各自的行為。而在javascript中有三種執(zhí)行上下文: 全局執(zhí)行上下文, 函數(shù)執(zhí)行上下文, eval執(zhí)行上下文。代碼在其執(zhí)行上下文中執(zhí)行。在javascript中只有一個(gè)全局執(zhí)行環(huán)境(根據(jù)宿主環(huán)境的不同,全局執(zhí)行環(huán)境的對(duì)象也不一樣)??梢杂性S多函數(shù)和eval執(zhí)行環(huán)境的實(shí)例,每次調(diào)用一個(gè)函數(shù)或eval,都會(huì)進(jìn)入對(duì)應(yīng)執(zhí)行環(huán)境執(zhí)行代碼。注意一個(gè)函數(shù)可能會(huì)產(chǎn)生無(wú)限上下文集合,因?yàn)槊看魏瘮?shù)調(diào)用自身都會(huì)產(chǎn)生一個(gè)新的執(zhí)行上下文
執(zhí)行上下文可以激活另一個(gè)執(zhí)行上下文,例如函數(shù)調(diào)用另一個(gè)函數(shù)(或者全局執(zhí)行上下文調(diào)用全局函數(shù))等等,邏輯上就成了一個(gè)堆棧。這被稱(chēng)為執(zhí)行上下文堆棧。
當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的上下文就會(huì)被推入一個(gè)棧中,如果在當(dāng)前函數(shù)中調(diào)用另一個(gè)函數(shù),當(dāng)前函數(shù)就會(huì)暫停執(zhí)行,并將執(zhí)行流傳遞給被調(diào)用函數(shù)(被調(diào)用函數(shù)同事可能是其他函數(shù)的調(diào)用者),被調(diào)用者被推入堆棧。當(dāng)被調(diào)用者的上下文結(jié)束后,將執(zhí)行流交還給調(diào)用者,調(diào)用者的繼續(xù)運(yùn)行代碼,直到結(jié)束后,棧將上下文彈出。
每個(gè)執(zhí)行上下文可以抽象成一個(gè)對(duì)象,都包含了一組屬性。
每個(gè)執(zhí)行上下文都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象。但是不包含函數(shù)表達(dá)式和this(因?yàn)樗皇且粋€(gè)變量)。
var foo = 10; function bar(){}; (function baz(){}) console.log(baz); //eror
全局上下文的變量對(duì)象
如果執(zhí)行上下文是一個(gè)函數(shù),則將其活動(dòng)對(duì)象作為變量對(duì)象,除了變量和函數(shù)聲明之外,他還存儲(chǔ)形式參數(shù)和arguments對(duì)象。
function foo(x, y) { var z = 30; function bar() {} (function baz() {}); } foo(10, 20);
我們發(fā)現(xiàn)baz不在活動(dòng)對(duì)象里。
作用域鏈本質(zhì)上就是根據(jù)名稱(chēng)查找變量(標(biāo)識(shí)符名稱(chēng))的一套規(guī)則。規(guī)則非常簡(jiǎn)單,在自己的變量對(duì)象里找不到變量,就上父級(jí)的變量對(duì)象查找,當(dāng)?shù)诌_(dá)最外層的全局上下文中,無(wú)論找到還是沒(méi)找到,查找過(guò)程都會(huì)停止。查找會(huì)在找到第一個(gè)匹配的變量時(shí)停止,被稱(chēng)為遮蔽效應(yīng)
var x = 10; (function foo(){ var y = 10; (function bar(){ var z = 10; console.log(x+y+z)![scope-chain.png][6] }) })
如下圖:
詞法作用域就是定義在詞法階段的作用域。換句話說(shuō),詞法作用域是由你在寫(xiě)代碼時(shí)將變量和塊作用域?qū)懺谀睦餂Q定的,無(wú)論函數(shù)在哪里被調(diào)用,也無(wú)論他如何被調(diào)用,他的詞法作用域只由函數(shù)被聲明位置決定。
在javascript中的eval函數(shù)可以接受一個(gè)字符串為參數(shù),并將其中的內(nèi)容視為在書(shū)寫(xiě)時(shí)就存在于程序中這個(gè)位置的代碼。
function foo(str, a){ eval(str); //欺騙 console.log(a, b); } var b = 2; foo("var b = 3;", 1); //1, 3
函數(shù)作用域有兩種方式
//函數(shù)聲明 function foo(){ var a = 3; console.log(a); }
//函數(shù)表達(dá)式 (function foo(){ var a = 2; console.log(a); })
兩者的區(qū)別在于它們的名稱(chēng)標(biāo)識(shí)符會(huì)被綁定到何處,第一段代碼中會(huì)被綁定到所在作用域中,第二段代碼被綁定在函數(shù)表達(dá)式自身的函數(shù)中而不是所在作用域中。
在javascript中沒(méi)有塊作用域,也就是說(shuō)在{...}中聲明的變量會(huì)泄露到外面作用域
if(true){ var foo = "dog" } console.log(foo); //dog function dosomething(i){ console.log(i); } for(var i = 0; i < 10; i++){ dosomething(i); } console.log(i);
而ES6中新增的let可以將變量綁定到所在的任意作用域(通常是{...}內(nèi)部),換句話說(shuō),let為其聲明的變量隱式的劫持了所在的塊作用域。
if(true){ var foo = "dog" } console.log(foo); //dog function dosomething(i){ console.log(i); } for(let i = 0; i < 10; i++){ dosomething(i); } console.log(i); //error總結(jié)
作用域其實(shí)是有執(zhí)行上下文中的變量對(duì)象和作用域鏈共同構(gòu)成的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/84920.html
摘要:下面我們就羅列閉包的幾個(gè)常見(jiàn)問(wèn)題,從回答問(wèn)題的角度來(lái)理解和定義你們心中的閉包。函數(shù)可以通過(guò)作用域鏈相互關(guān)聯(lián)起來(lái),函數(shù)內(nèi)部的變量可以保存在其他函數(shù)作用域內(nèi),這種特性在計(jì)算機(jī)科學(xué)文獻(xiàn)中稱(chēng)為閉包。 寫(xiě)這篇文章之前,我對(duì)閉包的概念及原理模糊不清,一直以來(lái)都是以通俗的外層函數(shù)包裹內(nèi)層....來(lái)欺騙自己。并沒(méi)有說(shuō)這種說(shuō)法的對(duì)與錯(cuò),我只是不想擁有從眾心理或者也可以說(shuō)如果我們說(shuō)出更好更低層的東西,逼格...
摘要:難怪超過(guò)三分之一的開(kāi)發(fā)人員工作需要一些知識(shí)。但是隨著行業(yè)的飽和,初中級(jí)前端就業(yè)形勢(shì)不容樂(lè)觀。整個(gè)系列的文章大概有篇左右,從我是如何成為一個(gè)前端工程師,到各種前端框架的知識(shí)。 為什么 call 比 apply 快? 這是一個(gè)非常有意思的問(wèn)題。 作者會(huì)在參數(shù)為3個(gè)(包含3)以?xún)?nèi)時(shí),優(yōu)先使用 call 方法進(jìn)行事件的處理。而當(dāng)參數(shù)過(guò)多(多余3個(gè))時(shí),才考慮使用 apply 方法。 這個(gè)的原因...
摘要:難怪超過(guò)三分之一的開(kāi)發(fā)人員工作需要一些知識(shí)。但是隨著行業(yè)的飽和,初中級(jí)前端就業(yè)形勢(shì)不容樂(lè)觀。整個(gè)系列的文章大概有篇左右,從我是如何成為一個(gè)前端工程師,到各種前端框架的知識(shí)。 為什么 call 比 apply 快? 這是一個(gè)非常有意思的問(wèn)題。 作者會(huì)在參數(shù)為3個(gè)(包含3)以?xún)?nèi)時(shí),優(yōu)先使用 call 方法進(jìn)行事件的處理。而當(dāng)參數(shù)過(guò)多(多余3個(gè))時(shí),才考慮使用 apply 方法。 這個(gè)的原因...
摘要:前言這段時(shí)間一直在消化作用域鏈和閉包的相關(guān)知識(shí)。而作用域鏈則是這套規(guī)則這套規(guī)則的具體運(yùn)行。是變量對(duì)象的縮寫(xiě)那這樣放有什么好處呢我們知道作用域鏈保證了當(dāng)前執(zhí)行環(huán)境對(duì)符合訪問(wèn)權(quán)限的變量和函數(shù)的有序訪問(wèn)。 前言:這段時(shí)間一直在消化作用域鏈和閉包的相關(guān)知識(shí)。之前看《JS高程》和一些技術(shù)博客,對(duì)于這些概念的論述多多少少不太清楚或者不太完整,包括一些大神的技術(shù)文章。這也給我的學(xué)習(xí)上造成了一些困惑,...
摘要:所以覺(jué)得把這個(gè)執(zhí)行的詳細(xì)過(guò)程整理一下,幫助更好的理解。類(lèi)似的語(yǔ)法報(bào)錯(cuò)的如下圖所示三預(yù)編譯階段代碼塊通過(guò)語(yǔ)法分析階段之后,語(yǔ)法都正確的下回進(jìn)入預(yù)編譯階段。另開(kāi)出新文章詳細(xì)分析,主要介紹執(zhí)行階段中的同步任務(wù)執(zhí)行和異步任務(wù)執(zhí)行機(jī)制事件循環(huán)。 一、概述 js是一種非常靈活的語(yǔ)言,理解js引擎的執(zhí)行過(guò)程對(duì)于我們學(xué)習(xí)js是非常有必要的??戳撕芏噙@方便文章,大多數(shù)是講的是事件循環(huán)(event loo...
閱讀 1082·2021-11-23 09:51
閱讀 2763·2021-08-23 09:44
閱讀 713·2019-08-30 15:54
閱讀 1489·2019-08-30 13:53
閱讀 3158·2019-08-29 16:54
閱讀 2595·2019-08-29 16:26
閱讀 1255·2019-08-29 13:04
閱讀 2379·2019-08-26 13:50