javascript
五个小例子教你搞懂 JavaScript 作用域问题
眾所周知,JavaScript 的作用域和其他傳統(tǒng)語(yǔ)言(類C)差別比較大,掌握并熟練運(yùn)用JavaScript 的作用域知識(shí),不僅有利于我們閱讀理解別人的代碼,也有助于我們編寫自己的可靠代碼。
下面筆者將使用五個(gè)小例子來給大家分析下 JavaScript 的作用域要注意的問題。
感謝?例子的來源?(這5個(gè)例子我做錯(cuò)了2個(gè) [嘿嘿,盡情鄙視吧],筆者就是要?死磕自己,奉獻(xiàn)大家!)
先給出五個(gè)例子:
每個(gè)例子旁邊都會(huì)給出答案的鏈接,如果你全部都正確了,你可以忽略這篇短文,并深深的鄙視下筆者。
例一: 答案
if (!("a" in window)) {var a = 1; } alert (a);?例二:答案
var a = 1,b = function a (x) {x && a (--x);}; alert (a);?例三:答案
function a (x) {return x * 2; } var a; alert (a);?例四:答案
function b (x, y, a) {arguments[2] = 10;alert (a); } b(1, 2, 3);?例五:答案
function a () {alert (this); } a.call (null);寫在答案前面的話:
頁(yè)面中JavaScript代碼在加載的時(shí)候,執(zhí)行順序是按照腳本標(biāo)簽<script>的順序一致的,但如果設(shè)置該標(biāo)簽async或defer屬性的話,則不能保證執(zhí)行順序(這點(diǎn)說起來慚愧,筆者沒有認(rèn)真測(cè)試過)。
JS代碼在解釋執(zhí)行前,會(huì)對(duì)進(jìn)行一次“預(yù)編譯”:
在預(yù)編譯的過程中,用var聲明的變量被設(shè)置為活動(dòng)對(duì)象(啥是活動(dòng)對(duì)象?)的屬性,默認(rèn)值為“undefined”,
以function定義的函數(shù)也被添加為活動(dòng)對(duì)象的屬性,它們的值就是函數(shù)的定義,匿名函數(shù)將不被解析(這句話啥意思?)。
變量初始化過程即賦值過程發(fā)生在解釋執(zhí)行期,而不是"預(yù)編譯期"。
例一答案:
有人大概會(huì)犯下面兩種情況的錯(cuò)誤:
情況一:if 分支里聲明a變量(var a = 1;),在if 外訪問不到變量a,所以對(duì)話框彈出 'undefined'。
這說明你對(duì)JavaScript 中沒有塊級(jí)作用域不太理解。請(qǐng)翻翻基礎(chǔ)書籍。筆者也會(huì)在后續(xù)的博文中 深入淺出地介紹JavaScript 變量、作用域和內(nèi)存問題。(到時(shí)候會(huì)給出鏈接的)
情況二:a 變量,不在window對(duì)象中,所以進(jìn)入if 分支,聲明 a 并賦值為 1,又由于JS沒有塊作用域,所以對(duì)話框彈出 1。
這說明你大概了解塊作用域(可能只是知道,但并不知道原理)。這時(shí)候你可能需要了解下啥是作用域鏈,多問問為什么沒有塊作用域(后續(xù)博文會(huì)推出的,但筆者仍希望你通過讀書的方式了解下)。
但是你還是對(duì)JS代碼執(zhí)行前的情況不太了解。
真正的情況是這樣的:
JS在預(yù)編譯的時(shí)候,var 聲明的變量 被設(shè)置為活動(dòng)對(duì)象(本例為 window )的屬性,默認(rèn)值是‘undefined’,
由于沒有塊作用域,所以if 塊中的 變量聲明被預(yù)編譯了,因此 a 是window的屬性 (a in window is true ) ,于是就能理解對(duì)話框彈出 'undefined'.
例二答案:
錯(cuò)誤的情況我就不多做介紹了,無非是彈出函數(shù)b的定義,或者彈出1。
下面解釋下本例的情況,本例的代碼執(zhí)行和下列代碼執(zhí)行是一樣的:
var a = 1; var b = function a (x) {x && a (--x); }; alert (a);第一行是一個(gè)變量的聲明。
第二行是函數(shù)字面量(函數(shù)表達(dá)式,詳細(xì)用法請(qǐng)參見:深入淺出 JavaScript 函數(shù) v 0.5),只不過該表達(dá)式?jīng)]有省略函數(shù)名(a),為什么不省略呢? 因?yàn)樵摵瘮?shù)要遞歸啊,不然咋遞歸?
但是殘酷的是,函數(shù)名在函數(shù)外部是未定義的,所以對(duì)話框彈出的是 1 。
針對(duì)本例還有一種說法是 逗號(hào)操作符,不知道是順序的還是倒序的,但是針對(duì)本例,順序還是逆序,真沒什么關(guān)系。
例三答案:
本例錯(cuò)誤的大部分情況都是彈出'undefined'.
錯(cuò)誤的原因就是不太了解JS的預(yù)編譯過程。
本例中JS的預(yù)編譯過程是這樣的,首先聲明變量 a (并未初始化喲),然后再初始化為function, 后面 var a ; 只是聲明變量,但是并未給a 賦值,所以其值還是function。
拿下面一段代碼做比較,可以印證上面的解釋:
function a (x) {return x * 2; } var a = 10; alert (a);誰(shuí)最后對(duì)同一個(gè)變量初始化(可以理解成賦值),最后變量就保留誰(shuí)的值。
例四答案:
理解本例的關(guān)鍵在于對(duì)參數(shù)對(duì)象的理解,arguments 的詳細(xì)介紹,在深入淺出 JavaScript 函數(shù) v 0.5中有詳細(xì)的介紹。
arguments 是一個(gè)特殊的對(duì)象,有數(shù)組的特性,但不是數(shù)組,arguments 對(duì)象不是只讀的,arguments [2] = 10;?
這句話就把參數(shù) a (其實(shí)可以理解成是函數(shù)的內(nèi)部變量) 更改為10,所以彈出 10。
arguments [2] 和 a 指向的是同一個(gè)值。
例五答案:
a 作為一個(gè)函數(shù),在JS中函數(shù)也是對(duì)象,對(duì)象當(dāng)然有屬性和方法了。
JavaScript 就為函數(shù)對(duì)象提供了兩個(gè)間接調(diào)用函數(shù)的方法 call() 和apply(),這兩個(gè)內(nèi)容的詳細(xì)解釋在深入淺出 JavaScript 函數(shù) v 0.5中有詳細(xì)的介紹。
call () 方法的語(yǔ)法是這樣的:
call([thisObj[,arg1[, arg2[, [,.argN]]]]]) // thisObj 是this要綁定的對(duì)象,后面是逗號(hào)分隔開的參數(shù)第一個(gè)參數(shù)是函數(shù)要執(zhí)行的作用域,本例中傳入null ,就是說函數(shù)的執(zhí)行沒有作用域的跳轉(zhuǎn),還是在聲明函數(shù)的作用域中執(zhí)行。
函數(shù)聲明的作用域?qū)ο鬄?window 對(duì)象,所以對(duì)話框彈出 [Object Window] 。
本例中涉及的 this 的用法,請(qǐng)參見深入淺出 JavaScript 函數(shù) v 0.5?。
寫在后面的話:
什么是活動(dòng)對(duì)象?
當(dāng)函數(shù)被調(diào)用,活動(dòng)對(duì)象(activation object) 就被創(chuàng)建了。它包含普通參數(shù)(formal parameters) 與特殊參數(shù)(arguments)對(duì)象(具有索引屬性的參數(shù)映射表)。
活動(dòng)對(duì)象在函數(shù)上下文中作為變量對(duì)象使用。
預(yù)編譯階段,匿名函數(shù)將不會(huì)被解析。這句話的理解:
一句話,函數(shù)聲明在"預(yù)編譯階段"被解析,函數(shù)字面量(函數(shù)表達(dá)式) 在執(zhí)行階段被解析。
例子:?
alert (add (2,3)); //5 function add(a,b) {return a+b; } // 函數(shù)聲明提升 //=====為了方便,筆者寫在了一起,在測(cè)試的時(shí)候,可不要在一個(gè)作用域中執(zhí)行喲=============== alert (add (2,3)); //error var add = function (a,b) {return a+b; }; //函數(shù)字面量,注意結(jié)尾的分號(hào)喲(細(xì)節(jié)很重要)。廣了個(gè)告::(祝大家勞動(dòng)節(jié)快樂,為我們這些勞動(dòng)者鼓掌)
更過關(guān)于函數(shù)的內(nèi)容,盡在?深入淺出 JavaScript 函數(shù) v 0.5
?
總結(jié)
以上是生活随笔為你收集整理的五个小例子教你搞懂 JavaScript 作用域问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 日媒:比亚迪高端汽车和产品出口让欧美厂商
- 下一篇: 使用 JavaScript 实现灵活的固