介紹JavaScript數據類型html
前人栽樹,後臺乘涼,本文參考瞭如下來源java
閱讀本文前,建議先閱讀如下文章segmentfault
var 變量 = 值; //其中只有兩種類型,一種是基本類型(相似於常量數據),一種是引用類型(對象)
首先,咱們要明確一點JavaScript的數據類型即爲值的數據類型。JavaScript中有6種數據類型(5種基本數據類型,1種引用類型)函數
undefined,null,number,boolean,stringthis
Objectspa
undefined型只有一個值,即特殊的undefined。使用var聲明變量但未對其加以初始化時,這個變量的值就就是undefined。例如prototype
var a; console.log(a===undefined);//true
null型也只有一個值,即null,從邏輯角度來看,null值表示一個空指針(這也是 使用typeof操做符檢測返回object的緣由)。若是定義的變量準備在未來用於保存對象,那麼最好將該變量初始化爲null而不是其它值。這樣只要直接檢測null值就能夠知道相應的變量是否已經保存了一個對象的引用了。代理
var a = null; console.log(typeof a);//"object"
實際上,ECMAScript中,能夠認爲undefined值是派生自null值的,因此undefined==null可是undefined!==null指針
console.log(undefined==null);//true console.log(undefined===null);//false
注意,必定要區分undefined和null的使用。通常來講,變量的值初始設置爲undefined(記得別顯示設置,由解釋器默認設置便可)。而引用型對象的初始值通常能夠顯式的設置爲null。或者能夠這樣理解undefined做爲基本數據類型的變量的初始值(默認設置),null做爲引用類型的變量的初始值(顯式設置)code
boolean型只有兩個字面值true,false。可是這兩個值和數字值不是一回事,所以true不必定等於1,而false也不必定等於0。
要將一個值轉爲boolean型等價的值,有兩種方案:
各種型與boolean型之間值得轉換關係以下表
數據類型 | 轉換爲true的值 | 轉換爲false的值 |
---|---|---|
boolean | true | false |
string | 任何非空字符串 | "" (空字符串) |
bumber | 任何非零數字值(包括無窮大) | 0和NaN |
undefined | 無 | undefined |
null | 無 | null |
Object | 任何對象 | 無 |
number類型用來表示整型和浮點數字,還有一種特殊的數值(NaN-not a number,這個數值用於表示一個原本要返回數值的操做數未返回數值得狀況-防止拋出錯誤)。
好比在其它語言中數值÷0都會致使錯誤,中止運行,可是在JS中。0/0、NaN/0會返回NaN,其它數字/0會返回Infinity,不會報錯。
任何涉及與NaN的操做都會返回NaN,JS有一個isNaN()函數,能夠判斷接收的參數是否爲NaN,或者參數轉化爲數字後是否爲NaN
console.log(NaN + 1); //NaN,任何涉及到NaN的操做都會返回NaN console.log(NaN === NaN); //false,NaN與任何值都不相等,包括NaN自己 console.log(isNaN(NaN)); //true,是NaN console.log(isNaN('10')); //false,被轉爲數字10 console.log(isNaN(true)); //false,被轉爲數字1 console.log(isNaN(null)); //false,被轉爲數字0 console.log(isNaN(undefined)); //true,返回NaN console.log(isNaN('hello')); //true,沒法轉換爲數字 console.log(0/0);//NaN,0/0返回NaN console.log(NaN/0);//NaN,NaN/0返回NaN console.log(1/0);//Infinity,其它數字/0返回Infinity console.log('1'/0);//Infinity,'1'成功轉爲數字 console.log('1a'/0);//NaN,'1a'轉爲數字失敗,變爲NaN console.log(Infinity/0);//Infinity,其它數字/0返回Infinity
注意:Infinity的類型是Number(不是基礎數據類型)
有兩種方法能夠將非number類型的值轉換爲number類型
console.log("1"*2);//12 console.log("1"/2);//0.5 console.log("1a"/2);//NaN
Number()函數的轉換規則以下:(引自參考來源)
console.log(Number(''));//0 console.log(Number('a'));//NaN console.log(Number(true));//1 console.log(Number('001'));//1 console.log(Number('001.1'));//1.1 console.log(Number('0xf'));//15 console.log(Number('000xf'));//NaN var a = {}; console.log(Number(a));//NaN a.toString = function(){return 2}; console.log(Number(a));//2 a.valueOf = function(){return 1}; console.log(Number(a));//1
parseInt()經常用於將其它類型值轉化爲整形。parseInt轉換與Number()有區別,具體規則以下
console.log(parseInt(''));//NaN console.log(parseInt('a'));//NaN console.log(parseInt('1234blue'));//1234 console.log(parseInt(true));//NaN console.log(parseInt('070'));//70,可是有一些環境中會自動轉換爲8進制56 console.log(parseInt('070',8));//56 console.log(parseInt('001.1'));//1 console.log(parseInt('0xf'));//15,16進制 console.log(parseInt('AF',16));//175,16進制 console.log(parseInt('AF'));//NaN console.log(parseInt('000xf'));//0 var a = {}; console.log(parseInt(a));//NaN a.toString = function(){return 2}; console.log(parseInt(a));//2 a.valueOf = function(){return 1}; console.log(parseInt(a));//2
parseFloat()轉換規則基本與parseInt()一致,只有以下不一樣點
console.log(parseFloat('1234blue'));//1234 console.log(parseFloat('1234blue',2));//1234 console.log(parseFloat('0xA'));//0 console.log(parseFloat('10.1'));//10.1 console.log(parseFloat('10.1.1'));//10.1 console.log(parseFloat('010'));//10
因爲Number()函數在轉換字符串時比較複雜並且不夠合理,所以在處理整數的時候更經常使用的是parseInt()函數-需注意最好第二個參數傳10,處理浮點數時更經常使用parseFloat()
另外注意,浮點數直接的計算存在偏差,因此兩個浮點數沒法用"="進行判斷
var a=10.2; var b= 10.1; console.log(a - b === 0.1);//false console.log(a - 10.1 === 0.1);//false,實際是0.09999999999999964 console.log(a - 0.1 === 10.1);//true
string類型用於表示由零或多個16位Unicode字符組成的字符序列,即字符串。字符串能夠由單引號(')或雙引號(")表示。任何字符串的長度均可以經過訪問其length屬性取得。
要把一個值轉換爲一個字符串有三種方式。
var a = 10; var b = '10' var c = {}; console.log(a.toString());//10 console.log(a.toString(8));//12 console.log(b.toString(8));//10,字符串基數沒用 console.log(String(c));//[object Object] console.log(c);//[object Object] console.log(c + '1');//[object Object]1 c.valueOf = function(){return 2}; console.log(String(c));//[object Object] console.log(c);//[object Object],valueOf沒用 console.log(c + '1');//21,隱式轉換時,valueOf起做用了 c.toString = function(){return 2}; console.log(String(c));//2 console.log(c);//2,toString起做用了 console.log(String(null));//"null",null和undefined能夠String()輸出 console.log(null.toString());//報錯,null和undefined不能toString
複雜 類型即引用型,也就是咱們常說的JS對象(包括普通的object型對象和function型對象)
對象其實就是一組數據和功能的集合。對象能夠經過執行new操做符後跟要建立的對象類型的名稱來建立。而建立Object的實例併爲其添加屬性和(或)方法,就能夠建立自定義對象。如
var o = new Object();//建立一個新的自定義對象{}
也就是說,除去基本類型,剩餘的就是引用型(包括內置對象,自定義對象等)都是基於Object進行拓展的
Object的每一個實例都具備下列屬性和方法:
參考 JS原型和原型鏈的理解
基本型和引用型最大的不一樣就是二者的存儲方式不一樣,如圖:
也就是說,上圖中,若是變量1的值變爲102,實際中棧內存中的101是不會變的,只是在棧內存中新開闢出一處,用來存放102這個常量。而後將變量1指向102。
而變量2因爲棧內存中存放的是指針,實際執行的是堆內存中的數據,因此變量2的值是能夠隨便改的(堆內存中的數據能夠更改)
這個問題有不少人提出過,由於按理說,null做爲JS的五大基本數據類型之一,那麼typeof null 爲和會===object呢?這與ECMAScript的歷史緣由有關。緣由以下:
請區分Object,Function,String與object,function,string。
具體參考: function類型與object類型的區別
好比有的人會說JS中有7中類型:5中基本數據類型和object與function(但其實咱們這這裏就將後面兩種之前算成引用型了)
或者用一句話總結更爲合適:"JS中有對象,每個對象都有一個本身的類型"。就比如每個動物都有屬於本身的類型同樣(人類,猴子...)。另外基本類型能夠認爲是一個不會改變的對象(便於理解)
至於爲何基本類型明明不是引用型,卻能像引用型同樣去使用一些基本數據操做(如toFixed,toString等)。請參考 基本數據類型爲何可以使用toString等操做
JavaScript中,基本類型有string,number等等,複雜類型中也拓展有String,Number等等。那麼這二者的區別是什麼呢?以下圖,簡單描述了基本類型中的string與複雜類型中的String的區別。
也就是說,string類型都是放在棧內存中的(相似於常量),若是string類型的變量的值改成另外一個string,那麼棧內存中原有的string並無變化,只不過是在棧內存中新開闢出一個string,而後改變變量的引用而已
而Strign的型的棧內存中只有指針,指向堆內存的數據。因此若是值進行了改變,是會直接修改堆內存中的數據內容,而棧內存中的指針並不會變。
這個一個知識點也是不少人疑惑的地方,明明只有一種複雜對象Object,但爲何一些函數類型的typeof 返回function,其它對象返回 object呢?
Function是最頂層的構造器。它構造了系統中全部的對象,包括用戶自定義對象,系統內置對象,甚至包括它自已。
null是天地之始,而後null生了Object,Object是萬物之母。而後Object有一個屬性constructor,恰巧能夠返回function的值,因此typeof Object爲function。而後Function是基於Object派生的。Function.prototype._proto_指向Object.prototype。(Function.constructor也返回function值)
參考 JS原型和原型鏈的理解
function a(){}; var b = function(){}; var c = new Function(); var d = new Object(); var e = new String(); var f = new Date(); console.log(typeof a);//function console.log(typeof b);//function console.log(typeof c);//function console.log(typeof Function);//function console.log(typeof Object);//function console.log(typeof d);//object console.log(typeof String);//function console.log(typeof e);//object console.log(typeof Date);//function console.log(typeof f);//object console.log(Object instanceof Function);//true console.log(Function instanceof Object);//true console.log(new Object() instanceof Object);//true console.log(new Object() instanceof Function);//false console.log(new Function() instanceof Function);//true console.log(new Function() instanceof Object);//true function Foo(){}; var foo = new Foo(); console.log(foo instanceof Foo);//true console.log(foo instanceof Function);//false console.log(foo instanceof Object);//true console.log(Foo instanceof Function);//true console.log(Foo instanceof Object);//true
==和===在JS中都有比較的意思,可是二者有着很大的不一樣,二者區別以下:
由於不一樣類型的值比較,==會將比較值轉換爲同一類型的值後 在看值是否相等。===的話會先判斷類型,若是類型不一樣,結果就是不等。
由於這類值得比較都是「指針地址」比較,不一樣的值,確定爲false
對於==會將複雜類型轉換爲基礎類型,進行值比較,對於===,因爲類型不一樣,直接爲false
var a = 1; var b = true; console.log(a == b); //true,轉換爲同一類型後值相等 console.log(a === b); //false,先比較類型不能,直接爲false var a = { 'test': '1' }; var b = { 'test': '1' }; console.log(a == b); //false,比較指針地址,不等 console.log(a === b); //false,比較指針地址,不等 var a = '11'; var b = new String('11'); console.log(a == b); //true,將高級類型String轉化爲基礎類型,值相等 console.log(a === b); //false,由於類型不一樣,直接爲false
JS的變量的值是鬆散類型的(弱類型),能夠保存任何類型的數據,JS內置的typeof能夠檢查給定變量的數據類型,可能的返回值以下:
console.log(typeof 'test'); //'string' console.log(typeof 101); //'number' console.log(typeof true); //'boolean' console.log(typeof undefined); //'undefined' console.log(typeof null); //'object' console.log(typeof function() {}); //'function' console.log(typeof {}); //object console.log(typeof new Date()); //object
instanceof用於判斷一個變量是不是某個對象的實例,主要是判斷某個構造函數的prototype屬性是否存在另外一個要檢查對象的原型鏈上。
//識別內置對象 - Array, Date等 console.log([] instanceof Array); //true console.log(new String('11') instanceof String); //true console.log('11' instanceof String); //false,由於11是簡單類型 //識別自定義對象類型以及父子類型 function Parent(x) { this.x = x; } function Child(x, y) { Parent.call(this, x); this.y = y; } //將Child的原型指向Parent,代表繼承關係,此時Child的構造變爲了Parent的構造 Child.prototype = new Parent(); //而後將構造函數換爲Child本身的 Child.prototype.constructor = Child; console.log(Child.prototype.constructor); //輸出構造函數是Child本身的 var person = new Child(1, 2); console.log(person.x + ',' + person.y); //1,2 console.log(person instanceof Child); //true console.log(person instanceof Parent); //true //不能識別簡單類型,由於instanceof後面只能是基於Object對象拓展的類型 console.log(101 instanceof number); //報錯,number is not defined
Object.prototype.toString的存在主要是爲了解決typeof和instanceof的不足,好比typeof沒法識別內置類型(Array Date等),而instanceof沒法識別簡單類型。因此纔有了這個。
Object.prototype.toString能夠識別5種簡單類型,以及所有內置類型(Array.Date等一些內置類型),可是沒法識別自定義對象類型
/** * @description 經過Object.prototype.toString來判斷傳入對象類別 * @param {Object} obj */ function type(obj) { //slice的做用,例如原本返回[object number],slice篩選出number return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); } console.log(type(1)); //number console.log(type('1')); //string console.log(type(true)); //boolean console.log(type(undefined)); //undefined console.log(type(null)); //null console.log(type(new Date())); //date console.log(type([])); //array console.log(type({})); //object function Test(a) { this.a = a; } console.log(type(new Test('1'))); //object,自定義類別只能識別爲object
前面說到JS中有基本類型和引用類型(對象類型、複雜類型各類說法都行)。請注意二者是有本質區別的。
var a = 10.1; console.log(a.toFixed(2));//10.10,臨時構建了個Number對象進行操做,操做完後銷燬了 a.foo = 'test'; console.log(a.foo); // undefined,由於a的值並非一個對象,沒法綁定屬性
上述代碼中,對基本類型的a
進行a.xx
操做時,會在內部臨時建立一個對應的包裝類型(好比number類型對應Number類型)的臨時對象。並把對基本類型的操做代理到對這個臨時對象身上,使得對基本類型的屬性訪問看起來像對象同樣。可是在操做完成後,臨時對象就扔掉了,下次再訪問時,會從新創建臨時對象,固然對以前的臨時對象的修改都不會有效了。