從前面三篇文章,咱們已經大體瞭解JavaScript的基本語法中的數據類型——數值型、字符串、布爾型、對象、數組、函數、null和undefined;
這篇文章將深刻探討這幾種數據類型在內存中的存儲方式、讀取方式和拷貝方式;javascript
在以前的文章,咱們瞭解到JavaScript中的變量根據數據的複雜程度可分爲原始數據類型和複雜數據類型;
如今,咱們將從數據內存存儲角度,將變量劃分爲基本類型值和引用類型值;
基本類型值:保存在棧內存的簡單數據段,包括數值、字符串、布爾值、null和undefined;
基本類型值在賦值時,直接將值賦給變量,訪問變量即訪問值,能夠直接操做保存在變量的值;
在進行基本類型值拷貝時,會在變量對象上建立一個新值,而後把值賦給另外一個變量;所以,在改變上述代碼中給a賦b的值後,再改變a的值,將不影響b的值,兩個變量的獨立的;
引用類型值:保存在堆內存中的對象,變量保存的是一個指向內存中對象的指針;
引用類型在賦值時是將保存在堆內存的對象的地址賦給變量,訪問變量實際訪問的是變量的指針,該指針指向對象,在讀寫(增刪改)操做時操做的是實際的對象,但在拷貝時則是指針;
全部由上述代碼可知:在把a賦值給b時實際拷貝的是a的指針,當改變對象的屬性值時,a賦予的對象的屬性值也會改變,由於兩者指向同一對象;
但有時候,咱們但願實現對象的真正拷貝而且切斷引用同一對象的聯繫,具體作法將會在下文具體講解;java
要想實現對象的深拷貝,第一步首先要知道數據的類型,否則後續工做將無從下手;
JavaScript中提供檢測數據類型的方法大體有3種:
typeof操做符typeof
操做符可以很好的區分基本類型值(null除外);
但對部分引用類型值就無能爲力,好比它沒法區分object、null和Array,此時就要藉助instanceof操做符
;
instanceof操做符instanceof
操做符能夠識別某個變量是不是某個對象的實例,藉助這個功能能夠進一步區分object、Array和null三者的區別;
可是,這還不足以區分object和Array,因此還須要藉助第3個方法識別數據類型;
Object.prototype.toString()方法
git
數據類型轉換以前在前面的文章分散到變量部分講解了一下,這裏爲了文章的系統性,從新將數據類型轉換的方法概括一下:github
任何類型數據轉換爲數值有4種方法:Number()
轉型函數、parseInt()
、parseFloat()
和+
操做符;
上述四種方法的區別在於Number和+
做用同樣能夠對任何類型數據進行轉型,而parseInt和parseFloat只能對數值和字符串轉型;數組
轉換爲字符串包括3種方法:轉型函數String()
,toString()
方法(null和undefined會報錯)和""
(做用等同於String()
);
函數
轉換爲布爾值有2種方法:轉型函數Boolean()
和!!
this
實現對象的深淺拷貝,首先要識別變量的數據類型,上一節咱們已經知道識別數據類型的方法,下面咱們能夠定義識別數據類型的函數並將其封裝在一個對象(通用庫)中;
通用庫的創建spa
(function(window){ window.Util = (function(){ // 1.判斷數據類型 function isNumber(el){ return typeof el === "number"; }; function isString(el){ return typeof el === "string"; } function isBoolean(el){ return typeof el === "boolean"; } function isObject(el){ return Object.prototype.toString.call(el) === "[object Object]" }; function isArray(el){ return Object.prototype.toString.call(el) === "[object Array]" }; function isSimpleType(el){ return this.isNumber(el) || this.isString(el) || this.isBoolean(el) }; return { isNumber:isNumber, isString:isString, isBoolean:isBoolean, isObject:isObject, isArray:isArray, isSimpleType:isSimpleType, } })(); })(window);
上述代碼首先使用數據類型判斷的方法判斷傳入的參數的數據類型;prototype
//對象或數組的拷貝 function shallowCopy(oldObj){ var newObj = {}; for(var key in oldObj){ if(!this.isSimpleType(oldObj[key])){ return "It doesn't match shallowCopy" } newObj[key] = oldObj[key] } return newObj; }; function cloneObject(oldObj){ var newObj = {}; for(var key in oldObj){ if(this.isObject(oldObj[key])){ newObj[key] = cloneObject(oldObj[key]) }else if(this.isArray(oldObj[key])){ newObj[key] = cloneArray(oldObj[key]) }else if(this.isSimpleType(oldObj[key])){ newObj[key] = oldObj[key] } } return newObj; }; function cloneArray(oldArr){ var newArr = []; for(var i = 0;i<oldArr.length;i++){ if(this.isArray(oldArr[i])){ newArr.push(this.cloneArray(oldArr[i])) }else if(this.isObject(oldArr[i])){ newArr.push(this.cloneObject(oldArr[i])) }else if(this.isSimpleType(oldArr[i])){ newArr.push(oldArr[i]) } } return newArr; }; function deepCopy(oldObj){ var newObj = {}; for(var key in oldObj){ if(this.isSimpleType(oldObj[key])){ newObj[key] = oldObj[key] }else if(this.isObject(oldObj[key])){ newObj[key] = this.cloneObject(oldObj[key]) }else if(this.isArray(oldObj[key])){ newObj[key] = this.cloneArray(oldObj[key]) } } return newObj; } return { isNumber:isNumber, isString:isString, isBoolean:isBoolean, isObject:isObject, isArray:isArray, isSimpleType:isSimpleType, cloneObject:cloneObject, cloneArray:cloneArray, shallowCopy:shallowCopy, deepCopy:deepCopy }
上面的代碼deepClone方法將對數組或對象的屬性進行遍歷,若是發現屬性值是基本類型,則直接賦值,若是發現是引用類型則調用cloneArray或cloneObject方法,這兩個方法將繼續遍歷引用類型的屬性值,直到遞歸到屬性值是基本類型值,從而完成對象的"深拷貝";
通用庫的代碼地址將發佈在【github】,以供童鞋參考;設計
經過閱讀本文,咱們能夠知道:
變量的數據類型根據其在內存中的存儲方式,可分爲基本類型值和引用類型值;
基本類型值是保存在棧內存中的簡單數據段,包括數值、字符串、布爾值、null和undefend,變量保存的是基本類型值的實際值;
引用類型值是保存在堆內存的對象,變量保存的是指向對象的指針;
判斷數據類型的方法包括typeof操做符、instanceof操做符、Object.prototype.toString()方法;
數據類型轉換的方法有轉換爲數值、轉換爲字符串和轉換爲布爾值;
咱們經過創建一個通用庫的方式,封裝對象的深淺拷貝方法;
最後,JavaScript核心知識點的基本語法部分將暫且告一段落,下一章將進入JavaScript核心知識點的標準庫部分;
《JavaScript高級程序設計(第3版)》