# javascript快速入門8--值,類型與類型轉換
## 原始值和引用值
在ECMAScript中,變量可以存放兩種類型的值,即原始值和引用值。
* 原始值(primitive value)是存儲在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。
* 引用值(reference value)是存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內存處。
為變量賦值時,ECMAScript的解釋程序必須判斷該值是原始類型的,還是引用類型的。要實現這一點,解釋程序則需嘗試判斷該值是否為ECMAScript的原始類型之一,即Undefined、Null、Boolean和String型。由于這些原始類型占據的空間是固定的,所以可將它們存儲在較小的內存區域——棧中。這樣存儲便于迅速查尋變量的值。
**在許多語言中,字符串都被看作引用類型,而非原始類型,因為字符串的長度是可變的。ECMAScript打破了這一傳統。**
如果一個值是引用類型的,那么它的存儲空間將從堆中分配。由于引用值的大小會改變,所以不能把它放在棧中,否則會降低變量查尋的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,所以把它存儲在棧中對變量性能無任何負面影響,如圖:

堆棧就像我們的書一樣,堆對應著書的正文內容,而棧對應的是書的目錄,章節標題是簡短的,所以在目錄里面可以放,而文章的內容則不能放在目錄里,我們只需要在目錄放一個對應文章的標題和頁碼.這樣,即可以在一本書中放大量的內容,又因為存在目錄,可以快速查找內容!
## 原始類型
如前所述,ECMAScript有5種原始類型(primitive type),即Undefined、Null、Boolean、Number和String。ECMA-262把術語類型(type)定義為值的一個集合,每種原始類型定義了它包含的值的范圍及其字面量表示形式。ECMAScript提供了typeof運算符來判斷一個值是否在某種類型的范圍內。可以用這種運算符判斷一個值是否表示一種原始類型;如果它是原始類型,還可以判斷它表示哪種原始類型。
typeof運算符有一個參數,即要檢查的變量或值。例如:
```
var str = "some thing";
alert(typeof str);//輸出string
var num =123;
alert(typeof(num));//輸出number,typeof運算符可以像函數一樣使用
//這主要運用于一些復雜的表達的以解決優先級問題
alert(typeof num*3);//輸出NaN,因為typeof優先于*
alert(typeof(num*3));//輸出number
```
對變量或值調用typeof運算符將返回下列值之一:
* "undefined",如果變量是Undefined型的
* "boolean",如果變量是Boolean型的
* "number",如果變量是Number型的
* "string",如果變量是String型的
* "object",如果變量是一種引用類型或Null類型的
**你也許會問,為什么typeof運算符對于null值會返回"object"。這實際上是JavaScript最初實現中的一個錯誤,然后被ECMAScript沿用了。現在,null被認為是對象的占位符,從而解釋了這一矛盾,但從技術上來說,它仍然是原始值。**
如前所述,Undefined類型只有一個值,即undefined。當聲明的變量未初始化時,該變量的默認值是undefined
```
var a;
alert(a);//輸出undefined
alert(typeof a);//輸出undefined
alert(a==undefined);//true
```
注意,值undefined并不同于未定義的值。但是,typeof運算符并不真正區分這兩種值。考慮下面的代碼:
```
var tmp;
alert(tmp);//undefined
alert(typeof tmp);//undefined
alert(typeof tmp2);//undefined
```
前面的代碼對兩個變量輸出的都是"undefined",即使只有變量tmp2是未定義的。如果不用typeof運算符,就對tmp2使用其他運算符,這將引起錯誤,因為那些運算符只能用于已定義的變量。例如,下面的代碼將引發錯誤:
```
alert(tmp3==undefined);//出錯,因為變量tmp3未聲明
```
當函數無明確返回值時,返回的也是值undefined,如下所示:
```
function tmp() {}//空函數,沒有返回值
alert(tmp());//undefined
```
另一種只有一個值的類型是Null,它只有一個專用值null,即它的字面量。值undefined實際上是從值null派生來的,因此ECMAScript把它們定義為相等的。但它們并不是嚴格相等的,因為它們是不同類型!
```
alert(null==undefined);//輸出true
```
盡管這兩個值相等,但它們的含義不同。undefined是聲明了變量但未對其初始化時賦予該變量的值,null則用于表示尚未存在的對象。如果函數或方法要返回的是對象,那么找不到該對象時,返回的通常是null。
```
var obj = document.getElementById("tmp");//頁面上沒有ID為tmp的元素
alert(obj);//null
```
Boolean類型是ECMAScript中最常用的類型之一。它有兩個值true和false(即兩個Boolean字面量)。即使false不等于0,0也可以在必要時被轉換成false,這樣在Boolean語句中使用兩者都是安全的。
```
var bool=true;
bool=false;
```
ECMA-262中定義的最特殊的類型是Number型。這種類型既可以表示32位的整數,還可以表示64位的浮點數。直接輸入的(而不是從另一個變量訪問的)任何數字都被看作Number型的字面量。例如,下面的代碼聲明了存放整數值的變量,它的值由字面量55定義:
```
var num =55;
```
整數也可以被表示為八進制(以8為底)或十六進制(以16為底)的字面量。八進制字面量的首數字必須是0,其后的數字可以是任何八進制數字(0到7),如下面代碼所示:
```
var num=020;//八進制10為十進制的16
alert(num);//雖然我們用八進制方法表示一個數,但輸出時,系統會自動輸出它的十進制表現形式
```
要創建十六進制的字面量,首位數字必須為0,其后接字母x,然后是任意的十六進制數字(0到9和A到F)。這些字母可以是大寫的,也可以是小寫的。例如:
```
var num=0x12;//十進制18
num=0xab;//171
alert(num);//輸出的仍是十進制的171
```
**注意!盡管所有整數都可表示為八進制或十六進制的字面量,但所有數學運算返回的都是十進制結果!**
要定義浮點值,必須包括小數點和小數點后的一位數字(例如,用1.0而不是1)。這被看作浮點數字面量。例如:
```
var num = 1;//整數
var num2=1.0;//浮點數
```
對于非常大或非常小的數,可以用科學記數法表示浮點值。采用科學記數法,可以把一個數表示為數字(包括十進制數字)加e(或E),后面加乘以10的倍數。不明白?下面是一個示例:
```
var num = 3E10;
alert(num);//30000000000
num=3.45E2;
alert(num);//345
```
也可用科學記數法表示非常小的數,例如0.00000000000000003可以表示為3-e17(這里,10被升到-17次冪,意味著需要被10除17次)。ECMAScript默認把具有6個或6個以上前導0的浮點數轉換成科學記數法。
幾個特殊值也被定義為Number類型的。前兩個是Number.MAX_VALUE和Number.MIN_ VALUE,它們定義了Number值集合的外邊界。所有ECMAScript數都必須在這兩個值之間。不過計算生成的數值結果可以不落在這兩個數之間。當計算生成的數大于Number.MAX_VALUE時,它將被賦予值Number.POSITIVE_INFINITY,意味著不再有數字值。同樣,生成的數值小于Number.MIN_VALUE的計算也會被賦予值Number.NEGATIVE_INFINITY,也意味著不再有數字值。如果計算返回的是無窮大值,那么生成的結果不能再用于其他計算。
事實上,有專門的值表示無窮大,即Infinity。Number.POSITIVE_INFINITY的值為Infinity,Number.NEGATIVE_INFINITY的值為-Infinity。
```
alert(Number.MAX_VALUE*2 == Infinity);//true
alert(Number.NEGATIVE_INFINITY == -Infinity);//true
```
由于無窮大數可以是正數也可以是負數,所以可用一個方法判斷一個數是否是有窮的(而不是單獨測試每個無窮數)。可以對任何數調用isFinit()方法,以確保該數不是無窮大。例如:
```
var a = 9E9999999999999999999999999999999999;//已經超過范圍了
if (isFinite(a)) {
alert("一個有窮數!");
} else {
alert("一個無窮數!");
}
```
最后一個特殊值是NaN,表示非數(Not a Number)。NaN是個奇怪的特殊值。一般說來,這種情況發生在類型(String、Boolean等)轉換失敗時。例如,要把單詞blue轉換成數值就會失敗,因為沒有與之等價的數值。與無窮大值一樣,NaN也不能用于算術計算。NaN的另一個奇特之處在于,它與自身不相等,這意味著下面的代碼將返回false:
```
alert(NaN);
alert(!!NaN);
alert(NaN == NaN);
```
出于這種原因,不推薦使用NaN值本身。函數isNaN()會做得相當好:
```
alert(isNaN(NaN));//true
alert(isNaN(123));//false
```
String類型的獨特之處在于,它是唯一沒有固定大小的原始類型。可以用字符串存儲0或更多的Unicode字符,由16位整數表示(Unicode是一種國際字符集,本書后面將討論它)。字符串中每個字符都有特定的位置,首字符從位置0開始,第二個字符在位置1,依此類推。這意味著字符串中的最后一個字符的位置一定是字符串的長度減1
字符串字面量是由雙引號(")或單引號(')聲明的。與Java不同的是,雙引號用于聲明字符串,單引號用于聲明字符。但是,由于ECMAScript沒有字符類型,所以可使用這兩種表示法中的任何一種。
String類型還包括幾種字符字面量,Java、C和Perl的開發者應該對此非常熟悉。下表列出了ECMAScript的字符字面量:
| 字 面 量 | 含 義 |
| --- | --- |
| \n | 換行 |
| \t | 制表符 |
| \b | 空格 |
| \r | 回車 |
| \f | 換頁符 |
| \\ | 反斜杠 |
| \' | 單引號 |
| \" | 雙引號 |
| \0nnn | 八進制代碼nnn(n是0到7中的一個八進制數字)表示的字符 |
| \xnn | 十六進制代碼nn(n是0到F中的一個十六進制數字)表示的字符 |
| \unnnn | 十六進制代碼nnnn(n是0到F中的一個十六進制數字)表示的Unicode字符 |
## 類型轉換
所有程序設計語言最重要的特征之一是具有進行類型轉換的能力,ECMAScript給開發者提供了大量簡單的轉換方法。大多數類型具有進行簡單轉換的方法,還有幾個全局方法可以用于更復雜的轉換。無論哪種情況,在ECMAScript中,類型轉換都是簡短的一步操作。
ECMAScript的Boolean值、數字和字符串的原始值的有趣之處在于它們是偽對象,這意味著它們實際上具有屬性和方法。例如,要獲得字符串的長度,可以采用下面的代碼:
```
var str ="some";
alert(str.length);
```
盡管"blue"是原始類型的字符串,它仍然具有屬性length,用于存放該字符串的大小。總而言之,3種主要的原始值Boolean值、數字和字符串都有toString()方法,可以把它們的值轉換成字符串。
**也許你會問,“字符串還有toString()方法,這不是多余的嗎?”是的,的確如此,不過ECMAScript定義所有對象都有toString()方法,無論它是偽對象,還是真的對象。因為String類型屬于偽對象,所以它一定有toString()方法。**
Boolean型的toString()方法只是輸出"true"或"false",結果由變量的值決定:
```
var bool=true;
alert(bool.toString());
```
Number類型的toString()方法比較特殊,它有兩種模式,即默認模式和基模式。采用默認模式,toString()方法只是用相應的字符串輸出數字值(無論是整數、浮點數還是科學記數法),如下所示:
```
var num=10;
alert(num.toString());
num=10.0;
alert(num.toString());//仍然是10
```
**在默認模式中,無論最初采用什么表示法聲明數字,Number類型的toString()方法返回的都是數字的十進制表示。因此,以八進制或十六進制字面量形式聲明的數字輸出時都是十進制形式的。**
采用Number類型的toString()方法的基模式,可以用不同的基輸出數字,例如二進制的基是2,八進制的基是8,十六進制的基是16。基只是要轉換成的基數的另一種叫法而已,它是toString()方法的參數:
```
var num=10;
alert(num.toString());//10
alert(num.toString(2));//1010
alert(num.toString(8));//12
alert(num.toString(16));//A
//對數字調用toString(10)與調用toString()相同,它們返回的都是該數字的十進制形式。
alert(num.toString(10));
```
ECMAScript提供了兩種把非數字的原始值轉換成數字的方法,即parseInt()和parseFloat()。正如你可能想到的,前者把值轉換成整數,后者把值轉換成浮點數。只有對String類型調用這些方法,它們才能正確運行;對其他類型返回的都是NaN。
```
alert(parseInt("12.23"));//12
alert(parseFloat("12.45"));//12.45
alert(parseFloat("12.23.34"));//12.23
alert(parseFloat("abc"));//NaN
alert(parseInt(true));//NaN
```
在判斷字符串是否是數字值前,parseInt()和parseFloat()都會仔細分析該字符串。parseInt()方法首先查看位置0處的字符,判斷它是否是個有效數字;如果不是,該方法將返回NaN,不再繼續執行其他操作。但如果該字符是有效數字,該方法將查看位置1處的字符,進行同樣的測試。這一過程將持續到發現非有效數字的字符為止,此時parseInt()將把該字符之前的字符串轉換成數字。例如,如果要把字符串"1234blue"轉換成整數,那么parseInt()將返回1234,因為當它檢測到字符b時,就會停止檢測過程。字符串中包含的數字字面量會被正確轉換為數字,因此字符串"0xA"會被正確轉換為數字10。不過,字符串"22.5"將被轉換成22,因為對于整數來說,小數點是無效字符。
parseInt()方法還有基模式,可以把二進制、八進制、十六進制或其他任何進制的字符串轉換成整數。基是由parseInt()方法的第二個參數指定的,所以要解析十六進制的值,需如下調用parseInt()方法:
```
alert(parseInt("AB",16));//171
alert(parseInt("10",2));//2
alert(parseInt("10",8));//8
```
如果十進制數包含前導0,那么最好采用基數10,這樣才不會意外地得到八進制的值。例如:
```
var str ="010";
alert(parseInt(str));//8
alert(parseInt(str,10));//10
```
**parseFloat()沒有基模式**
## 強制類型轉換
還可使用強制類型轉換(type casting)處理轉換值的類型。使用強制類型轉換可以訪問特定的值,即使它是另一種類型的。ECMAScript中可用的3種強制類型轉換如下:
* Boolean(value)——把給定的值轉換成Boolean型
* Number(value)——把給定的值轉換成數字(可以是整數或浮點數)
* String(value)——把給定的值轉換成字符串
用這三個函數之一轉換值,將創建一個新值,存放由原始值直接轉換成的值。這會造成意想不到的后果。
當要轉換的值是至少有一個字符的字符串、非0數字或對象時,Boolean()函數將返回true。如果該值是空字符串、數字0、undefined或null,它將返回false。可以用下面的代碼段測試Boolean型的強制類型轉換。
```
var b1 = Boolean(""); //false - 空字符串
var b2 = Boolean("hello"); //true - 非空字符串
var b1 = Boolean(50); //true - 非零數字
var b1 = Boolean(null); //false - null
var b1 = Boolean(0); //false - 零
var b1 = Boolean(new object()); //true - 對象
```
Number() 函數的強制類型轉換與 parseInt() 和 parseFloat() 方法的處理方式相似,只是它轉換的是整個值,而不是部分值。
parseInt() 和 parseFloat() 方法只轉換第一個無效字符之前的字符串,因此 "1.2.3" 將分別被轉換為 "1" 和 "1.2"。用 Number() 進行強制類型轉換,"1.2.3" 將返回 NaN,因為整個字符串值不能轉換成數字。如果字符串值能被完整地轉換,Number() 將判斷是調用 parseInt() 方法還是 parseFloat() 方法。
下表說明了對不同的值調用 Number() 方法會發生的情況:
| 用法 | 結果 |
| --- | --- |
| Number(false) | 0 |
| Number(true) | 1 |
| Number(undefined) | NaN |
| Number(null) | 0 |
| Number("1.2") | 1.2 |
| Number("12") | 12 |
| Number("1.2.3") | NaN |
| Number(new Object()) | NaN |
| Number(50) | 50 |
最后一種強制類型轉換方法 String() 是最簡單的,因為它可把任何值轉換成字符串。要執行這種強制類型轉換,只需要調用作為參數傳遞進來的值的 toString() 方法,即把 12 轉換成 "12",把 true 轉換成 "true",把 false 轉換成 "false",以此類推。強制轉換成字符串和調用 toString() 方法的唯一不同之處在于,對 null 和 undefined 值強制類型轉換可以生成字符串而不引發錯誤:
```
var s1 = String(null); //"null"
var oNull = null; var s2 = oNull.toString(); //會引發錯誤
```
在處理 ECMAScript 這樣的弱類型語言時,強制類型轉換非常有用,不過應該確保使用值的正確。
- 介紹
- HTML/CSS 教程
- 第 1 章 HTML5 概述
- 第 2 章 基本格式
- 第 3 章 文本元素
- 第 4 章 超鏈接和路徑
- 第 5 章 分組元素
- 第 6 章 表格元素
- 第 7 章 文檔元素
- 第 8 章 嵌入元素
- 第 9 章 音頻和視頻
- 第 10 章 表單元素[上]
- 第 10 章 表單元素[中]
- 第 10 章 表單元素[下]
- 第 11 章 全局屬性和其他
- 第 12 章 CSS 入門
- 第 13 章 CSS 選擇器[上]
- 第 14 章 CSS 顏色與度量單位
- 第 15 章 CSS 文本樣式[上]
- 第 15 章 CSS 文本樣式[下]
- 第 16 章 CSS 盒模型[上]
- 第 16 章 CSS 盒模型[下]
- 第 17 章 CSS 邊框與背景[上]
- 第 17 章 CSS 邊框與背景[下]
- 第 18 章 CSS 表格與列表
- 第 19 章 CSS 其他樣式
- 第 20 章 CSS3 前綴和 rem
- 第 21 章 CSS3 文本效果
- 第 21 章 CSS3 文本效果
- 第 23 章 CSS3 邊框圖片效果
- 第 24 章 CSS3 變形效果[下]
- 第 25 章 CSS3 過渡效果
- 第 26 章 CSS3 動畫效果
- 第 27 章 CSS 傳統布局[上]
- 第 27 章 CSS 傳統布局[下]
- 第 28 章 CSS3 多列布局
- 第 29 章 CSS3 彈性伸縮布局[上]
- 第 29 章 CSS3 彈性伸縮布局[中]
- 第 29 章 CSS3 彈性伸縮布局[下]
- 第 30 章 使用 Emmet 插件
- Bootstrap 教程
- 第 1 章 Bootstrap 介紹
- 第 2 章 排版樣式
- 第 3 章 表格和按鈕
- 第 4 章 表單和圖片
- 第 5 章 柵格系統
- 第 6 章 輔組類和響應式工具
- 第 7 章 圖標菜單按鈕組件
- 第 8 章 輸入框和導航組件
- 第 9 章 路徑分頁標簽和徽章組件
- 第 10 章 巨幕頁頭縮略圖和警告框組件
- 第 11 章 進度條媒體對象和 Well 組件
- 第 12 章 列表組面板和嵌入組件
- 第 13 章 模態框插件
- 第 14 章 下拉菜單和滾動監聽插件
- 第 15 章 標簽頁和工具提示插件
- 第 16 章 彈出框和警告框插件
- 第 17 章 按鈕和折疊插件
- 第 18 章 輪播插件
- 第 19 章 附加導航插件
- 第 20 章 項目實戰--響應式導航[1]
- 第 20 章 項目實戰--響應式輪播圖[2]
- 第 20 章 項目實戰--首頁內容介紹[上][3]
- 第 20 章 項目實戰--首頁內容介紹[下][4]
- 第 20 章 項目實戰--資訊內容[5,6]
- 第 20 章 項目實戰--案例和關于[7]
- javaScript 教程
- javascript快速入門1--JavaScript前世今生,HelloWorld與開發環境
- javascript快速入門2--變量,小學生數學與簡單的交互
- javascript快速入門3--分支判斷與循環
- javascript快速入門4--函數與內置對象
- javascript快速入門5--數組與對象
- javascript快速入門6--Script標簽與訪問HTML頁面
- javascript快速入門7--ECMAScript語法基礎
- javascript快速入門8--值,類型與類型轉換
- javascript快速入門9--引用類型
- javascript快速入門10--運算符,語句
- javascript快速入門11--正則表達式
- javascript快速入門12--函數式與面向對象
- javascript快速入門13--BOM——瀏覽器對象模型(Browser Object Model)
- javascript快速入門14--DOM基礎
- javascript快速入門15--節點
- javascript快速入門15--表單
- javascript快速入門16--表格
- javascript快速入門17--事件
- javascript快速入門18--樣式
- javascript快速入門19--定位
- javascript快速入門20--Cookie
- javascript快速入門21--DOM總結
- javascript快速入門22--Ajax簡介
- javascript快速入門23--XHR—XMLHttpRequest對象
- javascript快速入門24--XML基礎
- javascript快速入門25--瀏覽器中的XML
- javascript快速入門26--XPath
- javascript快速入門27--XSLT基礎
- PHP 教程
- 第一章 如何加載運行已發布的PHP項目
- 第二章 PHP基礎
- 第三章 操作符與控制結構
- 第四章 數學運算
- 第五章 數組
- 第六章 目錄與文件
- 第七章 自定義函數
- 第八章 字符串處理
- 第九章 正則表達式
- 第十章 日期與時間
- 第十一章 表單與驗證
- 第十二章 會話控制
- 第十三章 上傳文件
- 第十四章 處理圖像
- 第十五章 MySQL 數據庫
- 第十六章 PHP 操作MySQL
- 第十七章 面向對象基礎
- 第十八章 面向對象的特性
- 第十九章 面向對象的工具