要成為一個優秀的前端工程師,系統的學習Javascript,有夯實的Javascript基礎,以及對語言本身的深刻的理解,是基本功。從Javascript數據類型開始,我將對Javascript知識體系進行系統的梳理。
今天的主題是Javascript數據類型。
ECMAScript中有5中簡單的數據類型,也即基本數據類型:Undefined、Null、Boolean、Number和String。還有一種復雜數據類型:Object,Object本質上是由一組無序的名值對組成的。
首先要介紹的是typeof操作符,因為ECMAScript是松散類型的,所以需要一種方式來檢測給定變量的數據類型,就是typeof了。對一個值使用typeof操作符可能返回以下某個字符串。
下面是幾個使用typeof操作符的例子:
var typeText = "Javascript"; alert(typeof typeText); //"string" alert(typeof (typeText)); //"string" alert(typeof 123); //"number"
一定注意,typeof是操作符,不是函數,所以上面第三行的代碼中的括號,雖然可以使用,但不是必需的,加上括號反而會讓人誤解。
這是第一個一定要詳細說明的Javascript數據類型。Undefined類型只有一個值,也即undefined。
在使用var聲明變量但是未對其進行初始化的時候,這個變量的值就是undefined。例如:
var text; alert(text == undefined); //true
這裡聲明了text變量,但是並未對其進行初始化,所以比較這個變量和undefined字面量,結果表明它們是相等的。其實上面的語句與下面的例子是等價的:
var text = undefined; alert(text == undefined); //true
但是,實際上我們並沒有必要在聲明變量的時候顯式的將其初始化為undefined。
令人困惑的是,對未初始化的變量執行typeof操作,會返回undefined值,而對未聲明的變量執行typeof操作符同樣也會返回undefined值。
var text; //這個變量聲明後默認獲得undefined值 //下面這個變量沒有聲明 //var message; alert(typeof text); //"undefined" alert(typeof message); //"undefined"
Null類型是要和undefined類型對比說明的。首先,Null類型也是只有一個值的數據類型。如其他語言一樣,null只表示一個空對象指針,這也正是下面代碼中用typeof才做服檢測null值時會返回“object”的原因。如下所示:
var text = null; alert(typeof text); //"object"
如果聲明的一個變量明確的是要在將來保存一個對象,顯式的將其初始化為null是一個好習慣,到時候只要直接檢查該變量的值是不是null值就可以判定該變量是不是已經保存了一個對象的引用了。
實際上,undefined值是派生自null值的,所以它們的相等行測試返回都是true:
alert(null == undefined); //true
在介紹其他數據類型之前,我先比較這兩個數據類型的深層次的不同點。
學習了《Javascript高級程序設計》和阮一峰大神的博客之後,我對這兩者的區別有了更深刻的認識:
null表示"沒有對象",即該處不應該有值。典型用法是:
(1) 作為函數的參數,表示該函數的參數不是對象。
(2) 作為對象原型鏈的終點。
Object.getPrototypeOf(Object.prototype); // null
undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。典型用法是:
(1)變量被聲明了,但沒有賦值時,就等於undefined。
(2) 調用函數時,應該提供的參數沒有提供,該參數等於undefined。
(3)對象沒有賦值的屬性,該屬性的值為undefined。
(4)函數沒有返回值時,默認返回undefined。
var i; i // undefined function f(x){console.log(x)} f() // undefined var o = new Object(); o.p // undefined var x = f(); x // undefined
Boolean類型只有兩個字面值:true和false。這兩個值是區分大小寫的,並且這兩個值與數字值1和0是兩回事。
雖然Boolean類型只有兩個字面值,但是ECMAScript所有類型都可以轉換為與Boolean中的這兩個字面值等價的值,只需要調用Boolean()函數即可:
var val = "Hi"; var valAsBoolean = Boolean(val);
所以,相應的,也就存在一個其他數據類型與Boolean字面值的對應關系,如下表所示:
數據類型 轉換為true的值 轉換為false的值 Boolean true false String 任何非空字符串 ""(空字符串) Number 任何非零數字值(包含無窮大) 0和NaN Object 任何對象 null Undefined 不適用 undefined
在程序運行的時候,比如在流控制語句中,識別程序自動執行相應的Boolean轉換是很重要的,請看下例:
var text = "Hi"; if(text){ alert(value is true); }
上面代碼在執行時,變量text就會被自動用Boolean()函數轉換為Boolean類型。如果還要用String類型的text的話,那麼就是一個重大錯誤了。所以一定要確切的知道在流控制語句中使用的是什麼變量。
Number類型使用IEEE754格式來表示整數和浮點數值。
Javascript中最基本的數值字面值格式是十進制整數,除此之外整數還可以通過八進制(八進制字面值第一位為0,後面是0~7的八進制數字序列)、十六進制(前兩位為0x,後跟任何十六位數字,0~9,及A~F)。在進行算術運算時,所有數值都將被轉換成十進制數值進行計算。
在Number類型中,我主要想說以下幾個問題:
1、永遠不要測試某個特定的浮點數值,請看下例:
if(a + b == 0.3) //不要做這樣的測試 alert("你得到了0.3!");
如果這裡a和b分別是0.05和0.25,或者是0.15和0.15都不會有問題,如果這兩個值是0.1和0.2,那麼測試就將無法通過。
2、數值范圍:
最小值:Number.MIN_VALUE = 5e-324 = -Infinity
最大值:Number.MAX_VALUE = 1.7976931348623157e+308 = Infinity
如果在計算當中超過了最大或最小,都會被相應的轉換為+Infinity或者-Infinity。
當計算0/0時,會得到NaN,計算正數/0會得到Infinity,計算負數/0會得到-Infinity。
3、NaN,即非數值,是一個特殊的值。這個數值用來表示一個本來要返回數值的操作數未返回數值的情況。
NaN的特點:第一、任何涉及NaN的操作都會返回NaN。因為ECMAScript中任何數值除以非數值都會返回NaN,從而不會影響其他代碼執行,所以這個特點在多步計算中可能會導致問題。其次、NaN與任何值都不想等,包括自身。
針對這兩個特點,ECMAScript定義了isNaN()函數,該函數接受一個任何類型的參數,函數會幫助我們確定這個參數是否是NaN。任何不能被轉換成為數值的值都會導致這個函數返回true。請看下例:
alert(isNaN(NaN)); //true alert(isNaN(10)); //false alert(isNaN("true")); //true
4、數值轉換
把非數值轉換成數值的方法有Number()、paserInt()、parseFloat(),其中Number()可以接受任意類型的參數,paserInt()、parseFloat()則專門用於轉換字符串。
Number()類型的轉換規則: (1)布爾值:true=1,false=0; (2)null=0; (3)undefined=NaN; (4)字符串: a: 字符串是數值,轉換成十進制,忽略前導0,如果以“0x”開頭,則按照十六進制解析成十進制(由此可見,八進制是個特殊的存在) b:字符串是空串,轉換為0; c:除此之外全部轉換成NaN; (5)對象:方法和isNaN()判斷對象的方法基本相同。alert(Number("hello world")); // NaN alert(Number("0011")); //11 alert(Number("0x10")); //16 alert(Number("")); //0
parseInt()函數是我們最常用的,它的轉換規則:
(1)忽略字符串前面的空格; (2)如果第一個字符不是數字字符或者正負號,返回NaN,空字符串同樣返回NaN; (3) 小數點在這個函數中被認為是非數值字符;alert(parseInt(" ")); //NaN alert(parseInt(" 123")); //123 alert(parseInt("123asjdllxcias")); //123 alert(parseInt("asd")); //NaN同時,parseInt()還可以接受第二個參數作為第一個參數的基數,即告訴函數第一個參數該使用什麼進制去解析。
alert(parseInt("12",8)); //10 alert(parseInt("12",16)); //18 alert(parseInt("1001",2)); // 9
parseFloat()函數與parseInt()類似,區別在於parseFloat()函數會一直忽略前導0,並且不支持第二個參數,最後,如果小數點後全是0,則會返回整數。
alert(parseFloat("0012.2")); //12.2 alert(parseFloat("0012.000000")); //12 alert(parseFloat("0012.2.33")); //12.2 第二個小數點字符無效
String 對象用於處理文本(字符串)。
創建 String 對象的語法:
new String(s); String(s);
參數 s 是要存儲在 String 對象中或轉換成原始字符串的值。
當 String() 和運算符 new 一起作為構造函數使用時,它返回一個新創建的 String 對象,存放的是字符串 s 或 s 的字符串表示。
當不用 new 運算符調用 String() 時,它只把 s 轉換成原始的字符串,並返回轉換後的值。
字符串是 JavaScript 的一種基本的數據類型。
String 對象的 length 屬性聲明了該字符串中的字符數。
String 類定義了大量操作字符串的方法,例如從字符串中提取字符或子串,或者檢索字符或子串。
需要注意的是,JavaScript 的字符串是不可變的(immutable),String 類定義的方法都不能改變字符串的內容。像 String.toUpperCase() 這樣的方法,返回的是全新的字符串,而不是修改原始字符串。
在較早的 Netscape 代碼基的 JavaScript 實現中(例如 Firefox 實現中),字符串的行為就像只讀的字符數組。例如,從字符串 s 中提取第三個字符,可以用 s[2] 代替更加標准的 s.charAt(2)。此外,對字符串應用 for/in 循環時,它將枚舉字符串中每個字符的數組下標(但要注意,ECMAScript 標准規定,不能枚舉 length 屬性)。因為字符串的數組行為不標准,所以應該避免使用它。
Object類是所有JavaScript類的基類(父類),提供了一種創建自定義對象的簡單方式,不再需要程序員定義構造函數。
創建對象:
var o1 = new Object(); var o2 = new Object; //有效,但不推薦省略括號
Object的每個實例都具有的屬性和方法:
作為ECMAScript中所有對象的基礎,Object類型還有很多東西要說,今天就先說到這裡,後面我將對Object進行更加深入的闡述。