The NoteBook of EricKong

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks
          jQuery片段:


           1 var
           2     // Will speed up references to window, and allows munging its name.
           3     window = this,
           4     // Will speed up references to #ff0000, and allows munging its name.
           5     undefined,
           6     // Map over jQuery in case of overwrite
           7     _jQuery = window.jQuery,
           8     // Map over the $ in case of overwrite
           9     _$ = window.$,
          10 
          11     jQuery = window.jQuery = window.$ = function( selector, context ) {
          12         // The jQuery object is actually just the init constructor 'enhanced'
          13         return new jQuery.fn.init( selector, context );
          14     },
          15 
          16     // A simple way to check for HTML strings or ID strings
          17     // (both of which we optimize for)
          18     quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
          19     // Is it a simple selector
          20     isSimple = /^.[^:#\[\.,]*$/;
          21 

             在這一節(jié),我們將討論同一段jQuery片段的另一個知識點:數(shù)據(jù)類型和對象。為了讓我們更好地理解代碼,我們必須對這一部分內(nèi)容深入了解。沒有牢固的基礎(chǔ),是不可能構(gòu)筑起堅實的堡壘的。

          內(nèi)置數(shù)據(jù)類型

          內(nèi)置數(shù)據(jù)類型,也稱作固有數(shù)據(jù)類型,也就是JS的基本的數(shù)據(jù)類型。首先,讓我們的大腦熱一下身:回想一下,我們所有編程語言中實際可能運用到的數(shù)據(jù)都有些什么?
          基本如你所想,但實質(zhì)上我們需要的只是有意義的文字而已。但對于電腦來說,它能認識的不是文字,而是邏輯電路中電平的高低。為此,我們在程序語言中,將這些高低電平轉(zhuǎn)換成0和1,并使用這些二進制的數(shù)字串構(gòu)造成人類更加好理解的數(shù)字邏輯。這些數(shù)字邏輯實際上就是所謂的數(shù)據(jù)類型了。(我承認我在胡說八道……)
          現(xiàn)在讓我們看看JS是怎么理解這些數(shù)字邏輯,來讓我們更好地使用它的(至少JS的設(shè)計者初衷是這樣)。


          undefined

          我們第一個看到的數(shù)據(jù)類型是undefined?;蛟S很多人都會懷疑到——你沒有搞錯吧?undefined也是一種數(shù)據(jù)類型?!然后,我可以很鎮(zhèn)定的告訴你,我沒搞錯……

          1 alert(undefined);// "undefined"
          2 alert(typeof undefined);// "undefined"
          3 alert(undefined instanceof Object);// "false"
          4 alert(undefined instanceof undefined);// 語法錯誤:instanceof不能對undefined運算
          5 alert(undefined instanceof Undefined);// 錯誤:"Undefined"未定義

          看到上面的例子后,你還有疑問嗎?
          聯(lián)系一下我們前面所說的內(nèi)容,如果調(diào)用一個沒有聲明的變量被直接調(diào)用,應(yīng)該是會報錯的,但上例沒有,這就證明了undefined是JS里固有的變量。而且,根據(jù)typeof的結(jié)果,這個變量的數(shù)據(jù)類型是undefined。但它不是一個Object。而且不能用instanceof來判斷他是不是undefined實例。
          那么,讓我們來小結(jié)一下:undefined是一種類似單態(tài)的數(shù)據(jù)類型,他在全局作用域中以變量標(biāo)識undefined存在,并且擁有唯一值undefined。
          除了上面所說的以外,還有一些需要注意的地方,請看下例:
           
          1 // 如何判斷一個變量是否聲明
          2 alert(typeof x == "undefined");// true
          3 alert(x==undefined);// 報錯:"x"未定義

          所以,如果你需要判斷一個變量是否已聲明,請使用typeof運算符,再和"undefined"這個字符串比較。如果你看得仔細,你或許會產(chǎn)生一個疑問:在上一節(jié)中不是說,如果在作用域鏈中找不到變量標(biāo)識的時候,不是會創(chuàng)建空值標(biāo)識嗎?如果你有此一問,那么我得贊你一下,你真的用心思考了!這個問題將在稍后解答。
           
          1 var x;
          2 alert(undefined == "undefined");// false
          3 alert(x==undefined);// true
          4 alert(x=="undefined");// false

          另外,別以為undefined和字符串"undefined"是相等的,undefined不是字符串,而是另一種數(shù)據(jù)類型。

          null

          相信看完undefined后,你已經(jīng)不再懷疑null也是一種數(shù)據(jù)類型了吧??墒莕ull又有何特別呢?請看:

          1 alert(null);// "null"
          2 alert(typeof null);// "object"
          3 alert(null instanceof Object);// false
          4 alert(null instanceof null);// 報錯:instanceof不能對null運算

          你有感到奇怪了么?奇怪在哪里呢?嗯。我也覺得奇怪:為啥typeof的運算結(jié)果會是“object”,但instanceof判斷又為false呢?但對于這個問題,能找到的唯一解答是如此描述的:
          “這點潛在的混淆是為了向下兼容。”
          但怎么向下兼容,我已經(jīng)不能考究也不想考究下去了。我能告訴大家的是typeof null的返回值“object”是ECMA-262中規(guī)定的內(nèi)容。并且這規(guī)定只是為了兼容性,實際上null并不是一個Object的實例。
          至此,我們再小結(jié)一下:null和undefined很相似,只是我們從根本上還是屬于兩種不同的數(shù)據(jù)類型。但是他們真的“不同”嗎?讓我們再來看看下面的例子:

          1 alert(null==undefined);// "true"
          2 alert(null===undefined);// "false"

          那么,看來JS解釋器一般認為null和undefined是相等的了,雖然在嚴(yán)格等于運算時結(jié)果是false。(據(jù)說這是為了兼容以往的瀏覽器中沒有undefined而設(shè)的。)
          由此引起了我們另一個思考:他們到底有何異同呢?實際上,導(dǎo)致他們嚴(yán)格等于運算返回false的是typeof的運算——在運算符節(jié)再詳細解釋吧。但他們其實還有一個語言規(guī)范層級的區(qū)別:undefined是作為Global對象的屬性存在的,而null則是ECMA規(guī)范中設(shè)定的一個字面值。換句話說,undefined是存放在Global中的屬性(所以像單態(tài)),而null是解釋執(zhí)行時產(chǎn)生的值。然而對他們的值作強制轉(zhuǎn)換還是相同的,如:

          1 alert(!undefined);// "true"  
          2 alert(!!undefined);// "true"  
          3 alert(!null);// "true"  
          4 alert(!!null);// "true"  

          // 因此我們在使用if作判斷的時候能直接判斷變量是否為空或未定義  
          1 alert(parseInt(undefined));// "NaN"  
          2 alert(parseInt(null));// "NaN"
           
          // 注意NaN連自己也是不相等 
          1 alert(!undefined);// "true"
          2 alert(!!undefined);// "true"
          3 alert(!null);// "true"
          4 alert(!!null);// "true"

          // 因此我們在使用if作判斷的時候能直接判斷變量是否為空或未定義
          1 alert(parseInt(undefined));// "NaN"
          2 alert(parseInt(null));// "NaN"

          // 注意NaN連自己也是不相等
          還值得注意的是,和其他語言不同,他們和0值是不相等的,除非轉(zhuǎn)換成布爾值:

          1 alert(undefined==0);// "false"  
          2 alert(null==0);// "false"  
          3 alert(!undefined==!0);// "true"  
          4 alert(!null==!0);// "true" 
          5 alert(undefined==0);// "false"
          6 alert(null==0);// "false"
          7 alert(!undefined==!0);// "true"
          8 alert(!null==!0);// "true"
           
          另外,它們都不帶屬性的:
          1 view plaincopy to clipboardprint?
          2 alert(null.a);// "錯誤: null has no properties"  
          3 alert(undefined.a);// "錯誤: undefined has no properties" 
          4 alert(null.a);// "錯誤: null has no properties"
          5 alert(undefined.a);// "錯誤: undefined has no properties"

          最后,提一點我在項目中經(jīng)常看到的,某些程序員喜歡將一些控件的屬性是否定義的判定交給字符串"undefined"和null,但實際上只有null在起作用呢。

          boolean

          下一個我們看到的類型是boolean,也就是我們常用來判斷真假的布爾型。它的值只有兩個:true和false。讓我們來看看它的特點:
           1 var x=true;
           2 alert(x);// "true"
           3 alert(typeof x);// "boolean"
           4 alert(!x==0);// "true"
           5 alert(x==1);// "true"
           6 alert(x==2);// "false"
           7 alert(parseInt(x));// "NaN"
           8 alert(parseInt(!x));// "NaN"
           9 x=null;
          10 alert(x);// "null"
          11 alert(typeof x);// "object"
          12 x=undefined;
          13 alert(x);// "undefined"
          14 alert(typeof x);// "undefined"



          從上例我們可以看到,true和1相等,false和0相等,但是他們不能轉(zhuǎn)換成1和0。并且,因為JS的弱數(shù)據(jù)類型,所以當(dāng)x被賦予true和false以外的值后,他們的數(shù)據(jù)類型將會改變。
          布爾型的使用通常是在分支控制上,是JS中很關(guān)鍵的數(shù)據(jù)類型之一。

          number

          接著我們遇到的數(shù)據(jù)類型是number。顧名思義,number型就是指存放數(shù)字的類型。在其他語言中,我們遇到的數(shù)字型變量可能很多,分得很細,例如:short,int,long,float,double等等。但在JS中,所有的數(shù)字都被歸納成數(shù)字型的數(shù)據(jù)?;叵胍幌氯绻覀儗φ蛿?shù)據(jù)作不能整除的運算后會有什么結(jié)果?嗯,不能整除的部分將被截斷。但在JS,結(jié)果會變得不一樣:
          1 var x=5;  
          2 alert(x/2);// "2.5" 
          3 var x=5;
          4 alert(x/2);// "2.5"


          為什么會這樣呢?因為JS實際上會把所有數(shù)字型的數(shù)據(jù)解釋成浮點數(shù)。也就是無論你使用的數(shù)字是不是整數(shù)也好,JS的解釋器都會把他看成浮點數(shù)的特例。
          雖然在數(shù)據(jù)類型上沒有其他語言的復(fù)雜,但是我們?nèi)匀恍枰鎸Φ氖撬芙忉尩臄?shù)值范圍。請看:

          1 var x=2;  
          2 alert(Math.pow(x,1023));// "8.98846567431158e+307  
          3 alert(Math.pow(x,1023)+Math.pow(x,1022));// "1.348269851146737e+308  
          4 alert(Math.pow(x,1024));// "Infinity"  
          5 // PS:JS 中以"e+n"表示10的n次方

          可以看到,當(dāng)數(shù)字超過2的1024次方減1后,該值就變?yōu)闊o限大(Infinity)了。我們可以用類似的方法再測出JS可以判定的數(shù)值范圍,但我在這里就先省去了(其實也就是正負的21024)。我們跟著規(guī)范走:JS遵守的浮點標(biāo)準(zhǔn)是IEEE 754,換成具體的數(shù)字來說,如果把科學(xué)計數(shù)法算上,JS的數(shù)字運算能力最大可以到±1.7976931348623157x10308,最小到±5x10-324。然而,在我們實際運算中,大多運算符都不能支持這么高位的運算,請看:
           
          1 var x=2;
          2 alert(999999999999999+x);// "1000000000000001"
          3 alert(999999999999999-x);// "999999999999997"
          4 alert(9999999999999999+x);// "10000000000000002"
          5 alert(9999999999999999-x);// "9999999999999998"

          上例很明顯可以看出,當(dāng)數(shù)位超過15位時,計算精度就可以丟失。那么,究竟這個有效精度范圍是怎樣的呢?
           
          1 var x=2;
          2 alert(Math.pow(x,53)-2);// "9007199254740990"
          3 alert(Math.pow(x,53)-1);// "9007199254740991"
          4 alert(Math.pow(x,53));// "9007199254740992"
          5 alert(Math.pow(x,53)+1);// "9007199254740992"
          6 alert(Math.pow(x,53)+2);// "9007199254740994"

          這次我們就可以明確了,加減運算精度是控制在253內(nèi)的。也就是說,如果我們要處理253以外的數(shù)字運算的話,我們必須使用另外的方法了——例如數(shù)位拆分運算(名字我亂起的,實際意思就是將精度不可控的數(shù)位拆分成兩個精度可控的小數(shù)去計算,最后由兩個小數(shù)生成計算結(jié)果)。雖然要使用這種大數(shù)運算的機會幾乎為零。

          雖然JS并不細分數(shù)字的數(shù)據(jù)類型,但是它對各種進制的數(shù)字還是有一定支持的。但就初始化用的字面值來說,數(shù)字型能支持的有八進制,十進制和十六進制。先看一下示例:

          1 alert(10);// "10"  
          2 alert(010);// "8"  
          3 alert(0x10);// "16" 
          4 alert(10);// "10"
          5 alert(010);// "8"
          6 alert(0x10);// "16"

          字面值中表示十進制的數(shù)字無須任何修飾,而且能定義小數(shù)。
          表示八進制的數(shù)字需以0開頭,但必須注意的是,后續(xù)的數(shù)字不能大于7,不然還是會被判斷為十進制數(shù)字面值的。八進制數(shù)能表示負值,但不能表示小數(shù)。論壇中曾經(jīng)有朋友遇到的問題就是因為八進制字面值引起的。因為他拿到的文本值是固定二位數(shù),而單一數(shù)位大于7的字面值將被判斷為十進制而正常運作,但進位后則變?yōu)?進制數(shù),所以實際值與預(yù)期值就不相等了。
          表示十六進制的數(shù)字需要以0x或0X開頭,后續(xù)數(shù)字為符合十六進制表示法的0-9或a-f的大小寫字母。同樣地,十六進制數(shù)能表示負值,但不能表示小數(shù)。
          從上例中,我們還能看到,無論我們用哪種進制的字面值,經(jīng)過JS解釋后,還是將會返回十進值值的 ——雖然內(nèi)部存儲必定還是二進制。我們也可以用方法轉(zhuǎn)換其的進制顯示。
          下面,我們看一下JS中的一些典型的字面值和可能產(chǎn)生誤會的字面值:

          另外,對于數(shù)字型的數(shù)據(jù),有以下幾個特殊值:
          a)NaN(not a number),意思不是一個數(shù),但它卻是數(shù)字型的一個值,當(dāng)對不適當(dāng)?shù)臄?shù)據(jù)進行數(shù)學(xué)運算時,例如字符串或未定義值,它將會作為運算結(jié)果返回。NaN不與任何值相等,包括它自己,但我們可以使用方法isNaN來判定一個值得是否NaN。
          b)Infinity,意思是無窮大,相對地,有負無窮大-Infinity。當(dāng)一個數(shù)大于等于21024或小于等于21024,會分別用他們的正負形式來表示。所有Infinity是相等的,當(dāng)然,區(qū)分正負地相等。
          PS:或許在規(guī)范中還有一個負零,字面值為-0。但是實際上,當(dāng)其輸出時,只是簡單的0而已。不過我沒對低版本的瀏覽器測試過。猜差要不就是低版本中會有所區(qū)分,要不就是存儲時的二進制碼有所區(qū)分。

          在這里說一個實用技巧:我們常會碰到需要把文本框中的數(shù)字的小數(shù)部分多余的0去掉。這個時候,我們可以使用數(shù)字型的特性:
          1 alert(5.0000);// "5"  
          2 alert("5.0000"-0);// "5"  
          3 alert(typeof("5.0000"-0));// "number" 
          4 alert(5.0000);// "5"
          5 alert("5.0000"-0);// "5"
          6 alert(typeof("5.0000"-0));// "number"

          利用減0把字符強制轉(zhuǎn)換成數(shù)字型后,尾數(shù)的0自然就去掉了。

          最后,要提醒一下,JS的浮點運算真的不怎么樣,很容易就會有精度丟失的:
          1 alert(0.1+0.2);// "0.30000000000000004" 
          2 alert(0.1+0.2);// "0.30000000000000004"


          解決方法有二:1)放大到整數(shù)來運算;2)對計算結(jié)果進行精度控制。

          string

          string,也就是我們最需要的字符串類型。任何其他類型,其實都是為了最終轉(zhuǎn)換成字符串中人類可以理解的語言而服務(wù)的。那么這個令人著迷的數(shù)據(jù)類型又有何特別呢?我們先來看看如何定義一個字符串:
          1 var test="this is a test"
          2 var test="this is a test";


          是不是很簡單呢?我也覺得也是。那么我們再來看點復(fù)雜的:
           1 alert('test again');  
           2 alert("Is it a 'test'?");  
           3 alert('How "test" things go on?');  
           4 alert("\"test\" is all right now!");  
           5 alert('That \'test\' sounds great!');  
           6 alert("\u0059\u0065\u0073");// "Yes" 
           7 alert('test again');
           8 alert("Is it a 'test'?");
           9 alert('How "test" things go on?');
          10 alert("\"test\" is all right now!");
          11 alert('That \'test\' sounds great!');
          12 alert("\u0059\u0065\u0073");// "Yes"


          這次是不是看到眼花繚亂呢?字符串里最“復(fù)雜”的應(yīng)用莫過于引號的使用和轉(zhuǎn)義符了。
          由于JS沒有單字符的數(shù)據(jù)類型——如Java中的char,所以單雙引號的成對使用時基本不存在區(qū)別——Java中單引號里的是單字符。而且單雙引號能互相嵌套使用,但單(雙)引號必須包含所有雙(單)引號,并且雙(單)引號中不能再出現(xiàn)單(雙)引號。另一種可以使單(雙)引號都能嵌套自身的方法是使用轉(zhuǎn)義符“\”。
          另外,string支持unicode字面值,他們以并且只能以“\u”開頭,后面跟四位的unicode編碼(不區(qū)分大小寫)。在定義后,所有的string都將按UTF16儲存,所以不用擔(dān)心輸出的時候JS沒有為你轉(zhuǎn)碼——當(dāng)然,可以轉(zhuǎn)碼的是unicode字面值。
          最后提一下,string實際上是存放在有序數(shù)列中的。

          object

          呼呼!總算來到最后一個內(nèi)置數(shù)據(jù)類型了。它的大名就是object!在Java中,Object類是所有類的基類,那么聲稱Java~Script的JS到底把object做了怎樣的定位呢?
          由于JS中沒有類的概念,所以就沒有了繼承。啊!等等,JS是存在繼承的,而它是依賴prototype而存在的。至于這一部分的內(nèi)容,我們放到prototype節(jié)里去討論。我們現(xiàn)在先來關(guān)心一下object這個數(shù)據(jù)類型有何特別。

          object實際上是屬性與方法的集合。在ECMA規(guī)范對其類型進行劃分如下:
          本地對象(Native Object):指獨立于宿主環(huán)境存在的對象,它可能是內(nèi)置對象,也可能是在運行時由構(gòu)造函數(shù)創(chuàng)建的對象,標(biāo)準(zhǔn)的本地對象是Global,Math,Object,Function,Number,Boolean,String,Array,Date,Math,RegExp和Error,非標(biāo)準(zhǔn)的本地對象則是指自建對象;
          內(nèi)置對象(Build-in Object):指獨立于宿主環(huán)境存在的對象,它們從JS進入運行時就能訪問,標(biāo)準(zhǔn)的內(nèi)置對象包括Global,Math,Object,Function,Number,Boolean,String,Array,Date,Math,RegExp和Error,也就是和標(biāo)準(zhǔn)的本地對象是一樣的。非標(biāo)準(zhǔn)的內(nèi)置對象則如JScript實現(xiàn)中的Enumerator等。但無論它是否標(biāo)準(zhǔn)的內(nèi)置對象,所有內(nèi)置對象都是本地對象;
          宿主對象(Host Object):指依賴于宿主環(huán)境存在的對象,例如所有瀏覽器中的window(BOM)和document(DOM)對象。所有不是本地對象的對象都是宿主對象。

          下面我們來看一下如何才能得到一個object:
           
           1 var a = new Object();  
           2 function B(){  
           3   this.b = 1;  
           4 }  
           5 var b = new B();  
           6 alert(a);// "[object Object]"  
           7 alert(b);// "[object Object]"  
           8 alert(typeof a);// "object"  
           9 alert(typeof b);// "object"  
          10 alert(typeof B);// "function"  
          11 alert(b.b);// "1" 
          雖然這個例子可能看不出區(qū)別,但是可以說得到一個Object的關(guān)鍵是關(guān)鍵字new。但在typeof運算中,遇到Function對象還是會返回"function"的。這個在稍后運算符節(jié)再討論。
          從上面的例子,我們可以看到,JS中獲取對象的方式和Java很相象。但實際上,它們的差別可大呢。這個留待對象中一一解說。
          內(nèi)部數(shù)據(jù)類型

          除了在代碼中我們可以使用的數(shù)據(jù)類型以外,JS中實際上還存在為了內(nèi)部運行機制而設(shè)的三種數(shù)據(jù)類型:Reference、List和Completion。


          Reference

          Reference是一種內(nèi)部數(shù)據(jù)類型,它是作為運算中間值存在的。它的內(nèi)部有兩個屬性:base object和property name。而它的內(nèi)部也有一些對應(yīng)的方法去獲取這兩個屬性。一般來說,base object里存放的是值,而property name里存放的是需要返回的標(biāo)識。
          前面曾經(jīng)提及作用域鏈找不到標(biāo)識時,返回的是一個空值標(biāo)識,其返回形式就是以Reference為數(shù)據(jù)類型傳輸?shù)?。所賦予的null值是存放于base object中的。而因為typeof的特性,在運算返回結(jié)果的時候,會判定base object值為null的Reference的最終typeof運算結(jié)果為"undefined"。而直接判定null的時候,因為null為一種數(shù)據(jù)類型,不需要經(jīng)過Reference,所以返回的值是規(guī)范中定義的"object"。

          List

          List也是一種內(nèi)部數(shù)據(jù)類型,也是作為運算中間值存在的。它具體作用于new運算符或函數(shù)調(diào)用時的參數(shù)列表。這些參數(shù)列表是簡單的有序數(shù)列,而且可以是任意長的。PS:它和ArrayList是兩種東西——一種是數(shù)據(jù)類型,另一種是對象。

          Completion

          和前面兩個內(nèi)部數(shù)據(jù)類型一樣,Completion也是作為中間值存在的。它是運作于終結(jié)返回操作的,例如return, break, continue和throw。它的內(nèi)部由三個要素構(gòu)成:type, value, target。每一個要素都分別有其可以指定的值,這些值如下表:

           

           



          posted on 2010-05-18 13:13 Eric_jiang 閱讀(860) 評論(0)  編輯  收藏 所屬分類: JavaScript
          主站蜘蛛池模板: 万安县| 印江| 静宁县| 上林县| 通海县| 胶南市| 钟祥市| 抚顺市| 河池市| 卓资县| 尖扎县| 邻水| 西青区| 土默特左旗| 阳新县| 温泉县| 冀州市| 鄂托克旗| 克东县| 新昌县| 农安县| 宁海县| 兴和县| 太白县| 峨眉山市| 天峨县| 江山市| 弥勒县| 云龙县| 托克托县| 紫阳县| 靖西县| 哈尔滨市| 聂荣县| 台北市| 云龙县| 萝北县| 佛山市| 无极县| 永新县| 奉节县|