一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

javascript變量的作用域

 四分之三光棍 2012-11-02

我們看一道題,出處為javaeye的某貼——這世界就是這樣,有些人喜歡制造問題,有人喜歡解決問題。制造問題的人為解決問題的人帶來就業(yè)機會……

var a=100;  
var b=true;  
function test(){  
    alert(a);  
    alert(b);  
    b=false;  
    alert(b);  
    var a=200;  
    alert(a/2);  
    alert(++Math.PI);  
    alert(Math.PI++);  
}  
test();

為什么第一個alert為undefined,而第二個為true。這問題也可以延伸為——alert(b)時怎么就會找外部的b,而alert(a)時就不會往外面找?!

我們都明白局部變量的優(yōu)先級大于全局變量,或者說內圍作用域的變量的優(yōu)先級比外圍的高。當JS引擎在當前作用域找不到此變量時,它就往外圍的作用域找。不過,在這之前,有一個嚴肅的問題是,究竟當前作用域存不存在這個變量。像javascript這樣的解釋型語言,基本分為兩個階段,編譯期(下面為符合大多數(shù)語言的稱呼習慣,改叫預編譯)與運行期。在預編譯階段,它是用函數(shù)來劃分作用域,然后逐層為其以 var 聲明的變量(下略稱為var變量)函數(shù)定義開辟內存空間,再然后對var變量進行特殊處理,統(tǒng)統(tǒng)賦初始值為undefined,如下圖:

由上圖,我們便可以推知,當前網(wǎng)頁擁有兩個a,一個b,一個test函數(shù)。如果在運行期用到除此以外的東東,如c函數(shù)或d變量啦,就會報未定義錯誤(用eval等非正常手段生成變量與函數(shù)的情況除外),此外,它們最多出現(xiàn)未賦值警告。

javascript的運行期是在為var變量與函數(shù)定義分配空間后立即執(zhí)行,并且是逐行往下執(zhí)行的。

  • 第1行它為外圍作用域的a賦值為100
  • 第2行它為外圍作用域的b賦值為true
  • 第3行進行test的作用域,我們簡稱為內圍作用域。
  • 第4行就立即調用內圍作用域的a,這時它還沒有來得及賦值呢!不過它已經(jīng)聲明過了,因此默認為其賦值為undefined(在預編譯階段,見圖),于是alert為undefined
  • 第5行就調用b時,JS引擎就拿起我畫的圖看了(笑),發(fā)現(xiàn)test的作用域內沒有b,眼睛往外望,發(fā)現(xiàn)b了,而b在第二行就賦值為true,于是alert為true。
  • 第6行為一個賦值操作,把外圍的b變量改賦為false。于是到第7行時,alert為false。以下說法不說了。

作為對比,我們改寫一下例子:

var a=100;  
var b=true;  
function test(){  
    alert(a);  
    alert(b);  
    var b=false;  
    alert(b);  
    var a=200;  
    alert(a/2);  
    alert(++Math.PI);  
    alert(Math.PI++);  
}  
test();

這時在test函數(shù)的作用域內,b也被聲明了。

掌握預編譯為var變量與函數(shù)定義分配空間這一事實后,許多問題就迎刃而解。我們看犀牛書上的一個例子。

var scope = "global";  
function f() {  
    alert(scope);              
    var scope = "local";       
    alert(scope);              
}  
f();

答案呼之欲出!

我們來看更復雜的例子。

Object.prototype.test = 'wrong';
var test = 'right';
(function f() {
    alert(test);
})();

這個問題的難點在于,運行期時,又生成一同名變量,它是附著于Object.prototype,究竟哪一個距離F()的作用域近一些呢?!測試結果是var test。于是我們有了下圖:

于是我們明白了,原來定義在函數(shù)外面的var變量并不位于window作用域的下一層。

我們繼續(xù)加深難度。

(function f() {
    alert(test);
})();
Object.prototype.test = 'ccc';
Object.test = "bbb"
window.test = "aaa";

報未定義錯誤,因為預編譯期時沒有符合要求的var變量,而在運行期時,和它同名的變量在調用時(第2行)也尚未建立起來!

如果這樣呢?!

Object.test = "bbb";
Object.prototype.test = 'ccc';
window.test = "aaa";
(function f() {
    alert(test);
})();

估計有很多人猜是bbb,其實是ccc!有人就不解了,不是對象的屬性的優(yōu)先級比其原型屬性的優(yōu)先級高嗎???

無錯,的確如此,不過對象的屬性是這樣定義的:

var o = {test:"eee"}

Object.test = “XXX”這樣定義,為類屬性,或稱靜態(tài)屬性。類屬性優(yōu)先級都是比實例屬性低的

通過這圖也教育我們,一定要用局部變量啊,要不,一層層往上爬,效率是多么低啊。另外,這圖也告訴我們,window是一個多么高級的存在啊(微軟最愛聽),Object都比它低一等,更別提什么繼承問題啦?。ㄔ贔F與IE中)

//顛覆常識的存在
alert(window instanceof Object);

搞定這個我們看最難的一題。類屬性,實例屬性,原型屬性,極晚綁定的屬性都考到了!不過實例屬性與類屬性已超出本文的討論范圍,恕不討論了。這些也不太難,很容易google到的,自己google吧。

function foo(){
  foo.abc = function(){alert('def')}
  this.abc = function(){alert('xyz')}
  abc = function(){alert('@@@@@')};
  var abc = function(){alert('$$$$$$')}
}
foo.prototype.abc = function(){alert('456');}
foo.abc = function(){alert('123');}
var f = new foo();
f.abc();
foo.abc();
abc();

藍色理想的人說這題出得不好,有錯。我說,有錯才好,這樣才能考出水平!十秒內做出正確答案,說明學會了。

答案:

最后歸納一下,JS引擎有兩個設置變量的機會。第一次在預編譯時期,所有var變量會分配到各自的作用域中,值一律為undefined。第二次在運行期,由于是逐行執(zhí)行,因此是可變的。我們可以通過eval與Function動態(tài)生成新的變量,它們的作用域都是可制定的,其他賦值語句,只是把變量固定于頂層作用域(window)中,或是僅僅是重新賦值。我們也可以用delete來刪除對象的屬性,迫使其往外走同名變量。with閉包會在其引用的對象的屬性被刪除后,在閉包的外圍尋找與此屬性同名的變量。有關with閉包請看我另一篇博文。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日本中文在线不卡视频| 日本人妻中出在线观看| 超薄肉色丝袜脚一区二区| 成人精品亚洲欧美日韩| 婷婷色香五月综合激激情| 中文字幕亚洲视频一区二区| 色婷婷视频国产一区视频| 九九久久精品久久久精品 | 在线免费国产一区二区| 国产成人av在线免播放观看av| 在线九月婷婷丁香伊人| 九九热视频网在线观看| 久久精品中文扫妇内射| 色婷婷日本视频在线观看 | 日韩国产亚洲欧美另类| 少妇视频一区二区三区| 欧美日韩一区二区三区色拉拉| 91亚洲国产—区=区a| 伊人色综合久久伊人婷婷| 国产高清精品福利私拍| 人妻少妇av中文字幕乱码高清| 东北老熟妇全程露脸被内射| 热情的邻居在线中文字幕| 亚洲高清欧美中文字幕| 欧美一区二区三区高潮菊竹| 国产精品推荐在线一区| 国产精品久久熟女吞精| 欧美日韩国产午夜福利| 亚洲欧美日本视频一区二区| 亚洲性生活一区二区三区| 日韩高清中文字幕亚洲| 日韩欧美中文字幕av| 亚洲欧美日本国产有色| 开心五月激情综合婷婷色| 国产精品美女午夜视频| 国产精品白丝久久av| 欧美黑人暴力猛交精品| 欧美综合色婷婷欧美激情| 国产色第一区不卡高清| 亚洲性生活一区二区三区| 欧美日本精品视频在线观看|