摘要:總結(jié)總而言之,作用域在語法分析時就已經(jīng)處理完啦,的作用域是靜態(tài)作用域,在運(yùn)行時只是上下文對象在一直發(fā)生變化。
JavaScript 的作用域和上下文對象this
從幾個有意思的js問題開始
為什么輸出的不是f2?
`var scope = "top"; var f1 = function() { console.log(scope); }; f1(); // 輸出 top var f2 = function() { var scope = "f2"; f1(); }; f2(); // 輸出 top`
我還能訪問closure,但this值改變
`function closure(arg){ var a ="closure"; console.log(a);//(1) closure console.log(this);//(2) obj對象 return function(){ console.log(a);//(4) closure console.log(arg); // (5) arg console.log(this);//(6) windowd對象 } } var obj ={ func:closure } function func () { setTimeout(obj.func("arg"),100); console.log("funcEnd");// (3)funcEnd } func()`
this會被綁定在某個對象上
`var b = "window.b" var funcFactory = function(){ var b ="func.b"; var obj ={ a:"obj.a", func:function(){ console.log(b) console.log(this.a); } } return obj; } var temp =funcFactory() var func = temp.func; temp.func();// 先出現(xiàn) func.b 后出現(xiàn)obj.a func();// 先出現(xiàn)func.b 后出現(xiàn) undefined`
4.函數(shù)執(zhí)行完了,this綁定在window上
`function func(){ var a=1; setTimeout(function(){ console.log(a) },100); } func();// 1`
深度理解js靜態(tài)作用域
js靜態(tài)作用域
在第一段代碼中很多人會理所當(dāng)然的認(rèn)為會打印出f2來,會說f2是個function,js是個以function為作用域劃分,然而事情往往事與愿違---最后打印出的是出乎意料的top。人人都知道js在執(zhí)行之前會進(jìn)行預(yù)處理(V8處理js還會先把它編程字節(jié)碼),很多人只知道在預(yù)處理的時候會出現(xiàn)var變量的提升(es6的let就不會啦)和function一等公民的預(yù)先處理。然而卻忽略了作用域的處理--- 函數(shù)作用域的嵌套關(guān)系是定義時決定的,而不是調(diào)用時決定的,也就 是說,JavaScript 的作用域是靜態(tài)作用域,又叫詞法作用域,這是因?yàn)樽饔糜虻那短钻P(guān)系可 以在語法分析時確定,而不必等到運(yùn)行時確定。
this與作用域的誰在變化
首先讓我們來理解下scope的概念---一段程序代碼中所用到的名字并不總是有效/可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。在網(wǎng)上總是有什么前端面試題問setTimeout或者setInterval里面的變量為什么會改變,給出的答案永遠(yuǎn)是千篇一律的作用域發(fā)生了變化,然而我們從第一段代碼中我們就知道js是一個在語法分析時作用域就已經(jīng)確定了的。那到底是什么發(fā)生了變化了呢?是this(學(xué)名上下文對象),this這個值在js中是很詭異的,等我有時間專門要拿出來講一講,this這個值是會在運(yùn)行時動態(tài)的發(fā)生變化的,比如call,apply,bind。至于setTimeout和setInterval一對兄弟,我想再分享一段代碼來解釋下
function func(){ var a=1; setTimeout(function(){ console.log(a) },100); while(true){ a=2; } } func();
四段代碼中你可以看見1,但在這段代碼中你永遠(yuǎn)也不會再控制臺上發(fā)現(xiàn)1 的影子,因?yàn)橹灰獩]執(zhí)行完func這個函數(shù),js永遠(yuǎn)不會去事件隊(duì)列里面查詢是否有事件發(fā)生。同時js的變量回收也是在執(zhí)行完一個函數(shù)后才執(zhí)行的。
this和作用域的匯總介紹
第三段代碼的匯總使用啦,temp會從function中發(fā)揮obj對象,在我們調(diào)用temp.func的時候,this值會被綁定在obj這個對象上,顯示console.log(b),因?yàn)閎是從作用域中拿到的,所以在語法分析時就已經(jīng)給設(shè)定好啦,所以在控制臺上打印出“func.b”,在調(diào)用this.a時,因?yàn)閠his被運(yùn)行時綁定在obj對象上,所以會直接在obj上找(如果對象沒有可以繼續(xù)向上找原形鏈),當(dāng)變量func去得到obj.func時,他只得到的是函數(shù)(不帶包含它的對象),this自動會綁在window上,所以只能打印出b來(在語法分析時就已經(jīng)注定了訪問哪個變量),所以在window上找不到a這個屬性,就導(dǎo)致了undefined的出現(xiàn)。
總結(jié)
總而言之,作用域在語法分析時就已經(jīng)處理完啦,JavaScript 的作用域是靜態(tài)作用域,在運(yùn)行時只是this(上下文對象)在一直發(fā)生變化。也就是一個在運(yùn)行前就完成劃分(詞法作用域Lexical Scope),一個是在運(yùn)行中改變(類似于動態(tài)作用域Dynamic Scope),嚴(yán)格意義上說JavaScript只是詞法作用域。
js只有function來劃分作用域。this的改變方式就大概有三種,第一種call,apply,bind方法(有點(diǎn)類似于c++的組合型配接器)this會被綁定在第一個參數(shù)對象,第二種事件方法,setTimeout和setInterval會被綁定在全局對象上,像點(diǎn)擊事件之類的會被綁定在dom對象上,第三種obj.func訪問對象里的function會被綁定在最里面的對象上,例如obj1.obj2.obj3.func會綁定在obj3上(有人會說function里面也可以寫this的屬性,對呀function也是繼承自O(shè)bject的呀,它自己本身就帶上下文對象的)
作用域可以訪問嵌套它的作用域值,而this是按著原形鏈去訪問它父級對象,注意啦就如上例obj1.obj2.obj3.func,obj3雖然是obj2的屬性,但不是繼承于obj2的,它繼承是通過它prototype屬性來繼承的,所以在obj3.func中this并不會去訪問obj2的屬性
后記
不希望以后有人會拿以上代碼來面試或以以上代碼去面試企業(yè),這些知識知道就好了,實(shí)戰(zhàn)能力和對業(yè)務(wù)的把控才是程序猿技術(shù)的關(guān)鍵。
[1](http://www.cnblogs.com/bennman/archive/2013/09/08/3309024.html)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/78886.html
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...
摘要:變量提升的理解語言的執(zhí)行規(guī)則先定義,后執(zhí)行變量定義函數(shù)聲明就屬于定義代碼的范疇注意函數(shù)聲明和函數(shù)表達(dá)式的區(qū)別說明幾種不同的使用場景要在執(zhí)行時才能確認(rèn)值,定義時無法確認(rèn)全局環(huán)境下的對象方法中的構(gòu)造函數(shù)中的事件函數(shù)中的觸發(fā)當(dāng)前事件的對象中的創(chuàng)建 變量提升的理解 js語言的執(zhí)行規(guī)則:先定義,后執(zhí)行變量定義、函數(shù)聲明就屬于定義代碼的范疇(注意函數(shù)聲明和函數(shù)表達(dá)式的區(qū)別) 說明this幾種不同的...
摘要:示例當(dāng)一個函數(shù)創(chuàng)建后,它的作用域鏈會被創(chuàng)建此函數(shù)的作用域中可訪問的數(shù)據(jù)對象填充。每一個運(yùn)行期上下文都和一個作用域鏈關(guān)聯(lián)。此時,作用域鏈中函數(shù)的所有局部變量所在的作用域?qū)ο髸煌坪螅L問代價變高了。 作用域 作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。 作用域鏈 函數(shù)對象有一個內(nèi)部屬性[...
摘要:查詢是在作用域鏈中,一級級的往上查找該變量的引用。作用域和作用域鏈作用域的概念,應(yīng)該兩張圖幾句話就能解釋吧。這個建筑代表程序中的嵌套作用域鏈。一層嵌一層的作用域形成了作用域鏈,變量在作用域鏈中的函數(shù)內(nèi)得到了自己的定義。 javascript作用域和閉包之我見 看了《你不知道的JavaScript(上卷)》的第一部分——作用域和閉包,感受頗深,遂寫一篇讀書筆記加深印象。路過的大牛歡迎指點(diǎn)...
閱讀 472·2021-11-22 12:05
閱讀 1531·2021-11-17 09:33
閱讀 3579·2021-11-11 16:54
閱讀 2659·2021-10-14 09:49
閱讀 4023·2021-09-06 15:01
閱讀 1820·2019-08-29 17:23
閱讀 693·2019-08-29 14:09
閱讀 712·2019-08-29 12:28