javascript中最經典也最受非議的一句話就是:javascript中一切皆是對象。這篇重點要提到的,就是任何jser都不陌生的Object和Array。
有段時間曾經很詫異,到底兩種數據類型用來存儲數據有什么不同。于是,我打算探究探究。
一、掌握三種數據類型
首先,一個前提必須掌握的,就是必須理解javascript的數據類型分類,主要分為以下三種:
第一種類型是標量(scalar),也就是一個單獨的字符串(string)或數字(numbers),比如"北京"這個單獨的詞。
第二種類型是序列(sequence),也就是若干個相關的數據按照一定順序并列在一起,又叫做數組(array)或列表(List),比如"北京,上海"。
第三種類型是映射(mapping),也就是一個鍵/值對(key/value),即數據有一個鍵名,還有一個與之相對應的鍵值,這又稱作散列/哈希(hash)或字典(dictionary),比如"首都:北京"。
從這里也可知道對象就是一種映射類型的數據,數組是一種序列類型的數據。
比較細致的解答,可以參考阮一峰的博文《數據類型和Json格式》
二、聲明和實例化方式
1.對象的聲明和實例化
//第一種方式 var obj = new Object(); obj.name = "wall"; //第二種方式 var obj = {}; obj.name = "wall"; //第三種方式 var obj = { "name" : "wall" }; //第三種方式的簡約版 var obj = { name : "wall" //key減少了一對雙引號 }; //第四種方式 var obj = {}; obj["name"] = "wall";
2.數組的聲明和實例化
//第一種方式 var arr = new Array(); arr[0] = "wall"; //第二種方式 var arr = []; arr[0] = "wall"; //第三種方式 var arr = ["wall"]; //第四種方式 var arr = []; arr.push("wall"); //詭異的第五種方式,也是后面講的一個重點 var arr = []; arr["name"] = "wall";
三、使用方式
//輸出對象中name的值 console.log(obj.name); //或 console.log(obj["name"]); //輸出數組中name的值 console.log(arr[0]); //輸出數組聲明的第五種方式中的值 console.log(arr["name"]);
四、比較
以上可以看出,其實在簡單的數據存儲要求上,選擇數組和選擇對象進行存儲,差別不是很大,而且兩者均可以用下標的方式進行訪問,所以有時自己都有疑惑到底二者區別到底在哪里。
最簡單的不同就是:對象,系統默認是沒有length屬性的,而數組是默認有length屬性的。而這,又牽扯出一個有趣的現象:
在chrome的控制臺下,輸出一個簡單的例子
到這里,肯定會有人感到奇怪,為什么變量b的長度會是0! 為什么不是1。
為了驗證我的想法,就再編寫一個例子:
原來,b["test"]這個鍵值并沒有放入數組的序列中去,那會跑哪里去了?于是我查了下b這個變量的結構,然后再重新實例化一個新的變量b,比較其不同,終于找到原因:
原來,test是作為數組的一個屬性值進行存儲,而不是添加到數組的數據序列中去,頓時豁然開朗,呵呵~
這里也可以得出一個結論:數組是一個可以存儲序列類型數據的對象,即是對對象的繼承和擴展。數組的序列類型數據,可以通過整數下標進行讀寫操作,而其自定義的屬性值,則可以通過對象訪問屬性值的方式進行訪問,二者互不干擾。
五、對象實例化中需要注意的地方
//第三種方式 var obj = { "name" : "wall" }; //第三種方式的簡約版 var obj = { name : "wall" //key減少了一對雙引號 };
雖然這兩種方式看起來沒什么不同,都可以使用obj.name進行訪問,但是這里推薦第三種方式,而不要用簡約版。
原因就是如果用簡約版的方式進行實例化,鍵名如果是javascript保留的關鍵字,在 ECMAScript 5 之前會拋出SyntaxError
的錯誤(來自javascript秘密花園的解釋)。
六、函數變量緩存的技巧
我就不多說,直接先上代碼:
//定義函數 var fun = function(options){ if(!arguments.callee.arr){ arguments.callee.arr = { "name":"wall", "who":"jser" }; console.log("init");//標識是否調用初始化 } return arguments.callee.arr[options]; } //訪問name console.log(fun("name")); //訪問who console.log(fun("who"));
運行結果如下:
所以,很明顯地,數據只要初始化一次,就會保存在當前函數對象下,作為它的一個屬性值,下次操作就可以避免重復性的工作了。
可能很多讀者還不是很明白arguments.callee是什么,其實它指向的就是調用當前方法的對象,也即是fun。
這樣寫的原因是,在實際生產過程中,多人協作編碼,可能有人會一不小心把你這里的function改個名字什么的,那緩存的作用就失效了,甚至會出錯。不過有個缺點就是在嚴格模式下,arguments.callee會被禁用。
最后,再貼上一個未做上面這個優化的代碼,其實效果也一樣(其實就是將arguments.callee替換成fun)。
//定義函數 var fun = function(options){ if(!fun.arr){ fun.arr = { "name":"wall", "who":"jser" }; console.log("init");//標識是否調用初始化 } return fun.arr[options]; } //訪問name console.log(fun("name")); //訪問who console.log(fun("who"));
另外,這里的arguments.callee也可以替換成this指針,不過,調用的時候就要注意this指針的指向,這里可以用new function()的方式調用。
via:cnblogs.com/walls/p/4281531.html
文章列表