JavaScript 數據類型
數據類型就是 JavaScript 中可操作的數據的類型。
數據類型分為值類型
與引用類型
。
在 ES6 之前,主要有以下數據類型:
- 值類型
- 字符串
- 數字
- 布爾
- null
- undefined
- 引用類型
- 對象
- 數組
- 函數
1. 為什么需要不同的數據類型
在學習自然數學的時候,所有的加法減法等操作都是針對數字的,數字加上操作符讓他們有了意義。
在學習語文課的時候,不同的詞語可以組合成句子,主謂賓語法與詞語相互結合賦予了句子意義。
在 JavaScript 中也是如此,配合數據類型才能知道怎么對數據進行操作。
上一小節有提到的字符串與數字就是如此。
如 3 + 4
,JavaScript碰到兩邊都是數字,就會做對應的加法操作。
程序需要不同類型的數據表示不同的內容,分別做對應的處理。
2. 值類型
2.1 字符串
字符串由字符組成,字符串在使用的時候會使用雙引號(")
或者單引號(')
包裹。
var str1 = '字符串';
var str2 = "字符串";
console.log(str1); // 輸出:"字符串"
console.log(str2); // 輸出:"字符串"
上述例子中,兩個變量都是字符串類型的,可以雙引號和單引號包裹的結果是一樣的。
但是如果需要在雙引號包裹的字符串中使用雙引號,或者在單引號包裹的字符串中使用單引號,需要使用\
進行轉義,否則會報錯,因為 JavaScript 無法知道字符串的結束位置。
var str1 = '使\'用\'單\'引\'號';
var str2 = "使\"用\"雙\"引\"號";
console.log(str1); // 輸出:"使'用'單'引'號"
console.log(str2); // 輸出:"使"用"雙"引"號"
// 以下代碼會報錯
var str3 = "哼"!";
var str4 = ''哼!';
大部分開發者會使用單引號包裹字符串。
因為為了網頁的動態展示、復雜交互等,需要用 JavaScript 書寫 HTML 模版,而 HTML 的屬性按照習慣是使用雙引號包裹的(XML 標準允許單引號和雙引號,在 HTML5 的標準中甚至不需要書寫引號)。
這樣如果使用 JavaScript 中的字符串表示 HTML 就會變成如下情況:
var html = "<div class=\"title text-red\" style=\"display: inline-block;\">我是一個紅色的標題</div>";
為了契合書寫 HTML 的習慣,防止代碼中充斥的大量的轉義,就會使用如下使用單引號的形式。
var html = '<div class="title text-red" style="display: inline-block;">我是一個紅色的標題</div>';
2.2 數字
數字是最好理解的一種類型,因為生活中都會接觸到。
數字可以細分為浮點數和整數,浮點數就是帶有小數位的數,但事實上在 JavaScript 只有64位的浮點數
,具體的范圍是 [-2^53 ~ 2^53]
,整數也使用浮點數表示。
數字類型也存在負數,如果數字的區間為 (0, 1)
,則可以省略小數點前的 0
。
var num1 = 5;
var num2 = .1;
var num3 = 0.5;
var num4 = -10;
var num5 = 884739573;
以上是數字的一些表示方式。
如果數字的大小超過最大值或者最小值,那他的值在 JavaScript 中會表示為 Infinity
和 -Infinity
。
var base = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
var num1 = 99999 * base;
var num2 = -99999 * base;
console.log(num1); // 輸出:Infinity
console.log(num2); // 輸出:-Infinity
這兩個值分別表示為無窮大
和無窮小
。
JavaScript 中還可以用數字表示二進制
、八進制
與十六進制
。
二進制是以 0b
開頭的數字。
var val10 = 0b1010;
var val8 = 0b1000;
console.log(val10); // 輸出:10
console.log(val8); // 輸出:8
在輸出的時候還是會以十進制的結果進行輸出。
八進制則可以用 0
開頭的數字表示。
var val56 = 070;
console.log(val56); // 輸出:56
十六進制使用 0x
開頭表示。
var val10 = 0xA;
console.log(val10); // 輸出:10
十六進制是比較常用的一種方式,二進制和八進制的表示使用相對較少。
2.3 布爾
布爾值表示兩種狀態,如同使用零和一區分狀態的開關一樣。
布爾值兩種狀態對應 true
和 false
兩個值。
通常 true
被稱為真值
,false
被稱為假值
,兩者也被統一稱為布爾值
。
var empty = true;
var isVIP = false;
通常在只有兩種狀態的情況下會使用布爾值。
以下值在轉換成布爾值的時候會轉換成 false
。
- null
- undefined
- NaN
- 0 ( 數字 0 )
- 空字符串
2.4 null
null
是一個非常特殊的類型,表示對象的值未設置,也可以簡單理解成空
,什么都沒有
。
通常null
會在應該獲取到一個對象,但是沒獲取到的時候進行使用,結合對象會更好理解。
在初始化一個變量的時候,有時候類型不確定,或者應該是一個對象,但還有設置值的時候會使用到null。
var obj = null;
2.5 undefined
undefined
從中文意思上理解就是不確定或者沒有定義。
一個變量在聲明后如果沒有賦值,他的值就是undefined
。
var age;
console.log(age); // 輸出:undefined
一個函數在沒有指定返回值的時候,默認就會返回undefined
。
function fn() {
console.log('我是名字為fn的函數');
}
var val = fn();
console.log(val); // 輸出:undefined
函數fn
沒有提供返回值,但val
的值為undefined
。
比較有趣的是,undefined
既是一種數據類型,在瀏覽器中又是作為全局變量存在的,也就是window
對象下的一個屬性。
console.log('undefined' in window); // 輸出:true
使用in
關鍵字可以校驗某個對象下是否存在某個屬性。這里的意思就是undefined
屬性是否在window對象
下存在。
控制臺會輸出布爾值true
,為一個真值,表示屬性是確實存在的。
3. 引用類型
3.1 函數
函數其實是一段 JavaScript
代碼,調用函數就會執行函數中的代碼。
使用 function
關鍵字就可以定義一個函數,簡單的函數語法如下:
function 函數名(參數) {
函數體;
return 返回值;
}
var ret = 函數名(參數1) // 調用函數
函數名就是函數的名字,在調用函數的時候會被使用到。
參數則是傳遞給函數的數據,函數內部可以訪問到傳進來的參數。
return
則標志著函數的結束,返回值會被作為結果進行返回。
function add(arg1, arg2) {
var sum = arg1 + arg2;
return sum;
}
var num1 = add(1, 2);
var num2 = add(4, 2);
console.log(num1); // 輸出:3
console.log(num2); // 輸出:6
上面這個例子就是聲明了一個名為 add
的函數,其功能就是把兩個參數求和并返回。
可以看到函數讓代碼更加有 意義
,調用 add
函數的地方可以很好的理解這里是在做求和操作,同時提高了代碼的復用率。
3.2 對象
對象由屬性和方法組成。
其格式如下:
var obj = {
屬性名1: 屬性值1,
屬性名2: 屬性值2,
方法名1: 方法1,
方法名2: 方法2,
'屬性名3': 屬性值3,
};
屬性名和方法名都為字符串,如果其符合變量命名規范,則可以不使用引號包裹。
本質上方法也可以算作一個屬性,通常在對象里一個屬性的屬性值為一個函數,就會稱之為方法。
var obj = {
name: '小明',
age: 12,
say: function() {
console.log('我叫' + this.name + ', 我的年齡是' + this.age + '歲');
},
'father-name': '小藍',
};
console.log(obj.name); // 輸出:小明
console.log(obj['father-name']); // 輸出:小藍
obj.say(); // 調用 say 方法,會輸出:我叫小明, 我的年齡是12歲
上述例子中的 obj
對象具有三個屬性(name、age、father-name)一個方法(say)。
屬性可以是任意的數據類型,格式為屬性名: 屬性值
,多個屬性則由逗號(,)
分隔,方法則只能為一個函數,通常會是一個匿名函數(函數相關的詳細內容可以查閱函數章節)。
通過對象.屬性
就可以訪問到對象屬性的屬性值,如果屬性名是一個不符合變量命名規范的值,則可以通過對象['屬性名']
進行訪問,方法同理,因為本質上方法也是屬性。
既然屬性可以是任意的數據類型,則也可以是一個對象:
var obj = {
name: '小明',
colors: {
hair: 'red',
eye: 'blue',
skin: 'white',
},
};
理論上在內存允許的情況下,可以進行無限層的對象嵌套。
以上的例子都是采用字面量
的方式創建一個對象,還有許多種方式可以創建對象。
如使用Object
構造一個新對象。
var obj = new Object();
obj.name = '小明';
obj.age = 16;
obj.colors = {
hair: 'red',
eye: 'blue',
};
console.log(obj.colors.hair); // 輸出:red
console.log(obj.name); // 輸出:小明
obj.name = '小紅';
console.log(obj); // 將會在控制臺輸出 obj 對象
通過 new Object()
就可以創建一個新的對象。
通過對象.屬性 = 屬性值
的方式就可以設置一個屬性和屬性值,這一方式遵循以下規則:
- 如果要賦值的屬性不存在,則會創建這個屬性并賦值
- 如果要賦值的屬性存在,則會修改這個屬性的值
另外還可以使用構造函數
、Object.create
等方式創建對象,具體請參考對象章節。
3.3 數組
數組是一組數據構成的列表。
數組由中括號包裹,每一項通過逗號
進行分隔:
var arr = [1, '2', 3, 4, 5];
console.log(arr[0]); // 輸出:1
console.log(arr[1]); // 輸出:"2"
和對象一樣的是,數組的每一項也可以是任意類型的數據。
如果需要訪問數組中的每一項可以通過數組[下標]
的格式進行訪問。
下標就是數組每一項的編號,這個編號從0
開始,第一項為0
,第二項為1
,以此類推。
數組可以理解成一種特殊的對象,他原生具有一些方法,如遍歷數組:
var arr = ['a', 'b', 'c'];
arr.forEach(function(item, index) {
console.log(item, index); // "a" 0, "b" 1, "c" 2
});
通過數組.forEach
的方式就可以遍歷數組,forEach
方法接受一個函數,這個函數在遍歷到每一項的時候會被調用,并將每一項的值和下標作為參數傳遞過來。
既然具有一些方法,同樣的也具有一些屬性,最常用的就是length
屬性:
var arr = [1, 2, 3];
console.log(arr.length); // 輸出:3
數組的 length
屬性會返回數組的長度。
4. 值類型和引用類型的區分方式
從內存角度出發,值類型放在內存棧中,引用類型則放在內存堆中。
引用類型的數據長度是不固定的,如對象所占用的空間很大一部分由屬性值決定,而屬性值又可以是任意類型。
另外最大的區別就如分類名一樣,引用類型的數據本身是指向內存上的一塊地址,操作的時候對地址上的值進行操作。
而值類型直接操作值,不論是復制或是修改都是直接產生一個新的值。
var obj1 = {
name: '小明',
};
var obj2 = obj1;
obj2.name = '小紅';
console.log(obj1.name); // 輸出:小紅
var val1 = 1;
var val2 = val1;
val2 = 2;
console.log(val1); // 輸出:1
通過上面的例子就可以看出引用類型和值類型在 JavaScript 程序中的區別。
引用類型在進行復制的時候,其實就是多了一個引用,操作的值是同一個。
而值類型進行復制后,則是一個新的值。
5. 小結
- 數據類型是比較重要的一個概念,在分類上分為引用類型和值類型。
- 值類型包括:字符串、數字、布爾、null、undefined。
- 引用類型包括:函數、對象、數組。
- 引用類型相對復雜,每一種類型也具有很多特性,其內容可以參閱對應的章節。