整理 JS變量做用域

1  js靜態屬性和實例屬性javascript

   原型屬性在實例化以後做爲類的實例屬性。可是實例屬性在實例化以後卻不能做爲原型屬性。html

[javascript] view plaincopyjava

  1. <html>  ruby

  2.     <head>  閉包

  3.         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  函數

  4.         <title>測試</title>  測試

  5.     </head>  ui

  6.     <body>  this

  7.         <mce:script type="text/javascript"><!--  google

  8.             function Man(name, age) {  

  9.                 //定義實例屬性  

  10.                 this.name = name;  

  11.                 this.age = age;  

  12.             }  

  13.               

  14.             //定義靜態屬性。默認性別是男,不排除變性,^v^  

  15.             Man.sex = '男';  

  16.             //定義原型屬性  

  17.             Man.prototype.phone = '123456';  

  18.             //除了name.sex和Man.prototype.phone其他所有是Undefined  

  19.             alert(Man.sex + "-----" + Man.prototype.phone + "--" + Man.name + "--" + Man.age + "--" + Man.phone);  

  20.             var man = new Man("Tom", 24);  

  21.             alert(Man.sex + "--" + man.name + "--" + man.age + "--" + man.phone);  

  22.             /** 

  23.              * 經過例子說明:原型屬性在實例化以後做爲類的實例屬性。 

  24.              * 可是實例屬性在實例化以後卻不能做爲原型屬性。 

  25.              */  

  26.           

  27. // --></mce:script>  

  28.     </body>  

  29. </html>  


2

javascript變量的做用域

不太會寫堂而皇之的開場白,直接進入主題。

咱們看一道題,出處爲javaeye的某貼——這世界就是這樣,有些人喜歡製造問題,有人喜歡解決問題。製造問題的人爲解決問題的人帶來就業機會……

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)時就不會往外面找?!

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

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

javascript的運行期是在爲var變量與函數定義分配空間後當即執行,而且是逐行往下執行的。

  • 第1行它爲外圍做用域的a賦值爲100

  • 第2行它爲外圍做用域的b賦值爲true

  • 第3行進行test的做用域,咱們簡稱爲內圍做用域。

  • 第4行就當即調用內圍做用域的a,這時它尚未來得及賦值呢!不過它已經聲明過了,所以默認爲其賦值爲undefined(在預編譯階段,見圖),因而alert爲undefined

  • 第5行就調用b時,JS引擎就拿起我畫的圖看了(笑),發現test的做用域內沒有b,眼睛往外望,發現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函數的做用域內,b也被聲明瞭。

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

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。因而咱們有了下圖:

因而咱們明白了,原來定義在函數外面的var變量並不位於window做用域的下一層。

咱們繼續加深難度。

( 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!有人就不解了,不是對象的屬性的優先級比其原型屬性的優先級高嗎???

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

var  o = {test: "eee" }

Object.test = 「XXX」這樣定義,爲類屬性,或稱靜態屬性。類屬性優先級都是比實例屬性低的

經過這圖也教育咱們,必定要用局部變量啊,要不,一層層往上爬,效率是多麼低啊。另外,這圖也告訴咱們,window是一個多麼高級的存在啊(微軟最愛聽),Object都比它低一等,更別提什麼繼承問題啦!(在FF與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。第二次在運行期,因爲是逐行執行,所以是可變的。咱們能夠經過eval與Function動態生成新的變量,它們的做用域都是可制定的,其餘賦值語句,只是把變量固定於頂層做用域(window)中,或是僅僅是從新賦值。咱們也能夠用delete來刪除對象的屬性,迫使其往外走同名變量。with閉包會在其引用的對象的屬性被刪除後,在閉包的外圍尋找與此屬性同名的變量。

相關文章
相關標籤/搜索