學一門編程語言,無非兩方面:一是語法,二是數據類型。類C語言的語法不外乎if、while、for、函數、算術運算等,面向對象的語言再加上object。
語法只是語言設計者預先做的一套規則,不同語言語法不盡相同,但都有一些共通點,對於熟悉一兩門編程語言的人,學其他的編程語言時,語法往往不是問題(當然,如果你一直學的是類C語言,那麼首次接觸lisp時肯定也要花些時間),學習的重點往往是數據類型及其相關操作上,不是有句老話:“數據結構+算法=程序”!其次,有些語言的語法本身就存在設計問題(javascript更甚),我們沒必要深究這些點,當然,如果你自诩geek,可以把玩把玩。
本文將對javascript中的數據類型做一個詳盡的介紹。
弱類型 vs 強類型
鑒於javascript的設計理念,javascript被設計成一種弱類型的語言。
說到這裡,難免要說一下,弱類型與強類型的區別。
一些人會誤以為這兩者的差別就是“強類型的語言在聲明一個變量時需要指明它的類型,而弱類型的則不用”。其實這種觀點是錯誤的。比如下面這個Java代碼片段:
復制代碼 代碼如下:
String s = "hello";
int l = s.getBytes().length;
編譯器是怎麼知道.length是合法的表達式呢?這是因為編譯器知道s的數據類型為String,當調用String的getBytes方法時,返回值的數據類型為byte[],所以.length是合法的表達式。
這兩者真正的區別是:
在強類型的語言,每個表達式的類型都能夠在編譯時確定,並且只允許適用於該類型的操作;
弱類型的語言允許對任意類型施加任何操作,只是這個操作有可能在運行時報錯。
數據類型
根據ECMAScript 5.1的規范,javascript中共有六種數據類型,分別為:Undefined, Null, Boolean, Number, String、Object。前五種屬於基本類型,最後一種屬於對象類型。
基本數據類型
Undefined類型只有一個值,為undefined,意味著“空值(no value)”,適用於所有數據類型。
Null類型只有一個值,為null,意味著“空對象(no object)”,只適用於對象類型。
Boolean類型有兩個值,為true與false
Number類型的值是遵循IEEE 754標准的64位浮點數的集合,類似於Java的double。沒有整型數據結構。此外還包含三個特殊的值:NaN、Infinity、-Infinity
String類型的值是有窮個Unicode字符的集合。必須用'或"括起來。
null與undefined
null與undefined都表示“沒有值(non-value)”的概念,如果嚴格區分:
- null表示空
- undefined表示不存在。沒有初始化的變量、函數中缺失的參數、函數沒有顯式return值時都為此值
在其他語言中,一般只用一個null來表示空值,javascript中為什麼多了個undefined呢?這是歷史原因造成的:
javascript采用了Java的語法,把類型分為了基本類型與對象類型,Java中用null來表示空對象,javascript想當然的繼承了過來;在C語言中,null在轉為數字時為0,javascript也采取同樣的方式:
復制代碼 代碼如下:
> Number(null)
0
> 5 + null
5
在javascript1.0時,還沒有異常處理(exception handling),對於一些異常情況(沒有初始化的變量、調用函數時缺失的參數等),需要標明為一種特殊的值,null本來是個很好的選擇,但是Brendan Eich同時想避免下面兩件事:
- 這個特殊值不應該有引用的特性,因為那是對象特有的
- 這個特殊值不應該能轉為0,因為這樣不容易發現程序中的錯誤
基於這兩個原因,Brendan Eich選擇了undefined,它可以被強轉為NaN。
復制代碼 代碼如下:
> Number(undefined)
NaN
> 5 + undefined
NaN
兩者在於JSON對象打交道時,結果也迥然不同:
復制代碼 代碼如下:
> JSON.parse(null)
null
> JSON.parse(undefined)
//Firfox SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
//Chrome SyntaxError: Unexpected token u
> JSON.stringify(null)
"null"
> JSON.stringify(undefined)
undefined
對象類型
javascript作為一門腳本語言,本身功能十分精簡,很多功能(文件讀寫、網絡等)都是由宿主環境提供。宿主環境與javascript語言的橋梁是對象,宿主環境通過提供一系列符合javascript語法的對象,提供各種各樣的功能。
在javascript面向對象編程這篇文章(如果你不知道prototype是什麼,強烈建議看看這篇文章)裡,我多次強調了對象在javascript中就是一系列的鍵值對,就像Java中的HashMap一樣,不過,javascript中對象的屬性可以有一些描述符(property descriptor),這在HashMap中是沒有的。
屬性描述符
屬性描述符分為兩類:
數據描述符(data descriptor),包含一系列boolean值,用以說明該屬性是否允許修改、刪除。
訪問描述符(accessor descriptor),包含get與set函數。
這兩種描述符都是對象,它們都擁有下面兩個boolean屬性:
configurable 用以指定該描述符是否允許修改、刪除。默認為false。
enumerable 用以指定在遍歷對象(使用for...in循環或Object.keys方法)的屬性時,是否訪問該屬性。默認為false。
除了上面這兩個共有屬性外,數據描述符還有下面兩個屬性:
- value 用以指定該屬性的值,默認為undefined
- writable 用以指定該屬性的值是否允許改變該屬性的值,默認為false
訪問描述符還有下面兩個屬性:
- get 用以指定訪問該屬性時的訪問器(getter,本質是個函數),該訪問器的返回值為該屬性的值。默認為undefined
- set 用以指定訪問該屬性時的賦值器(setter,本質是個函數),該賦值器的接受一個參數。默認為undefined
我們可以使用Object.defineProperty來設置對象的屬性描述符。例如:
復制代碼 代碼如下:
// using __proto__
Object.defineProperty(obj, 'key', {
__proto__: null, // no inherited properties
value: 'static' // not enumerable
// not configurable
// not writable
// as defaults
});
通過上面這個例子可以看出,描述符具有繼承的特點,我們這裡顯式的把描述符對象的__proto__設為null,就避免了從Object.prototype中繼承相應屬性。當然我們也可以顯式地設置描述符的所有屬性:
復制代碼 代碼如下:
// being explicit
Object.defineProperty(obj, 'key', {
enumerable: false,
configurable: false,
writable: false,
value: 'static'
});
這樣的效果和第一段代碼的效果是一樣的。
下面再舉一個訪問描述符的例子:
復制代碼 代碼如下:
// Example of an object property added with defineProperty with an accessor property descriptor
var bValue = 38;
Object.defineProperty(obj, 'key', {
get: function() { return bValue; },
set: function(newValue) { bValue = newValue; },
enumerable: true,
configurable: true
});
需要注意的是,不能混淆了訪問描述器與數據描述器。下面這樣寫是錯誤的:
復制代碼 代碼如下:
// You cannot try to mix both:
Object.defineProperty(obj, 'conflict', {
value: 0x9f91102,
get: function() { return 0xdeadbeef; }
});
// throws a TypeError: property descriptors must not specify a value
// or be writable when a getter or setter has been specified
typeof
如果想在運行時獲知某變量的類型,可以使用typeof操作符。typeof的返回值如下表:
其中有一處需要注意,那就是typeof null == "object",按照ECMAScript 5.1標准,Null類型應該是個基本類型,為什麼這裡返回object呢?原因是這樣的:
在javascript 1.0中,javascript中的值是用一個類型標志(type tag)和一個實際值這樣的結構表示的,對象的類型標志為0,null在C語言中表示NULL指針(0x00),所以null的類型標志就為0了。
以上就是本文的全部內容了,有需要的小伙伴參考下吧。