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