javascript的變量類型真的很要人糾結,即使你是很有經驗的js工程師,你也很難說清楚js的類型和分類。
最近在講javascript入門指南的時候,有人提出數組為什么不是基本類型,我通過演示typeof []的結果來說明,數組是對象類型派生出來的,而不是六種基本類型。
其實要理解javascript的變量類型很簡單,就是我們要找到一個劃分的標準。
在很多書中都提到了javascript的變量類型,每本書都有不同的劃分標準,如果按照typeof和instanceof的返回值來區分,可以把javascript的變量類型分為兩套類型系統:基本類型和對象類型衍生出來的對象類型系統。
基本類型包括:undefined,number,boolean,string,object,function,他們之前通過typeof的返回值來區分。
第二套對象類型系統是由第一套系統衍生發展而來的,例如前面提到的Array,還有Null,Number,Boolean等等,對象類型可以通過instanceof來判斷。
那么對象類型中的Number和基本類型中的number又是什么關系呢?他們又是什么區別呢?
答案就是,他們是映射關系,即下例:
var a = new Number(123);console.log(a.valueOf()===123);//truevar b = new String(123);console.log(b.valueOf()===123);//falseconsole.log(b.valueOf()==='123');//true
obj.valueOf()返回的是該對象的原始值。
這里再談談值類型和引用類型的問題,在javascript中:undefined、string、number和boolean是“值類型”,而object與function是“引用類型”。所有引用類型都可以看著Object()的子類,所以任意函數也是Object()的子類。
怎么理解值類型和引用類型呢??看下面的例子:
var a = 123; var b = a; a = 1; console.log(b);//123
var c = [1,2,3]; var d = c; d[0] = 4; console.log(c);//[4,2,3]
看見上面的示例,有些人可能就暈了,很多人一不小心就改變了引用類型的值,而自己還不清楚程序出現了什么問題!
當值類型a賦值給b時,這時候會在內存中給b分配空間,所以a和b是完全獨立的兩個變量。
而c和d之間,通過賦值,產生了引用關系,兩者之間都指向了同一個數組,所以修改其中一個值會改變對方的值。
在實際開發中一定要記住這點,不要亂賦值,否則會犯上面的錯誤。例如下例,可以先把使用的site賦值出來,這樣變量e是一個值類型,不會產生引用問題。
var c = {site:'js8.in'};var d = c;var e = d.site;d.site = 'weibo.com';console.log(e);//js8.in
ECMAScript中函數的參數是按值傳遞的,當參數為引用類型值時便按引用傳遞是一種錯誤或者不全面的說法。
對于參數為基本類型值的情況,很容易理解。但對于引用類型值的參數,卻很容易讓人誤解為是按引用傳遞的。如下面的例子:
function fn(arg){ arg.site = 'js8.in'; arg = new Object(); arg.site = 'weibo.com';}var obj = new Object();fn(obj);console.log(obj.site)//js8.inconsole.log(window.arg);//undefined
示例中,如果arguments是按照引用類型傳遞的,那么obj.site應該為weibo.com,但是結果卻是js8.in。
事實是這樣的:當參數為引用類型值時的確是按引用傳遞的。
至于的你后面舉的例子也是一個引用傳遞的,obj把引用傳給arg,arg引用的內存空間和obj的一致,所以設置site為js8.in的時候,obj能接受到。后面你new了一個新的Object,相當于開了一個新的內存空間,然后arg引向了那塊新內存,但是obj引用的內存還是原來那塊,所以后面site賦值了,obj不改變。這個跟C/C++的指針有點像。至于window.arg為undefined,是因為js的作用域是詞法作用域,function外的當然引用不了function內的,與值傳遞或者引用傳遞木有關系啊(來自周某欣)。
最后來一張周愛民大神的javascript類型關系圖: