一、棧(stack)和堆(heap)數組
stack爲自動分配的內存空間,它由系統自動釋放;函數
而heap則是動態分配的內存,大小不定也不會自動釋放。編碼
二、基本類型和引用類型spa
基本類型:存放在棧內存中的簡單數據段,數據大小肯定,內存空間大小能夠分配。3d
5種基本數據類型有Undefined、Null、Boolean、Number 和 String,它們是直接按值存放的,因此能夠直接訪問。指針
引用類型:存放在堆內存中的對象,變量實際保存的是一個指針,這個指針指向另外一個位置。每一個空間大小不同,要根據狀況開進行特定的分配。code
當咱們須要訪問引用類型(如對象,數組,函數等)的值時,首先從棧中得到該對象的地址指針,而後再從堆內存中取得所需的數據。對象
三、傳值與傳址blog
var a = [1,2,3,4,5]; var b = a; var c = a[0]; alert(b);//1,2,3,4,5 alert(c);//1 //改變數值 b[4] = 6; c = 7; alert(a[4]);//6 alert(a[0]);//1
a-b:傳址 a-c:傳值遞歸
三、淺拷貝
前面已經提到,在定義一個對象或數組時,變量存放的每每只是一個地址。當咱們使用對象拷貝時,若是屬性是對象或數組時,這時候咱們傳遞的也只是一個地址。所以子對象在訪問該屬性時,會根據地址回溯到父對象指向的堆內存中,即父子對象發生了關聯,二者的屬性值會指向同一內存空間。
let a = { key1: 111 } function shallowCopy(p){ let c = {} for(let i in p){ c[i] = p[i] } return c } a.key2 = ['a','b'] let b = shallowCopy(a) b.key3 = 333 console.log('a', a) /** a:key1:111 key2:['a','b'] */ console.log('b', b) /** b:key1:111 key2:['a','b'] key3:333 */ /**淺拷貝: 爲b添加新屬性,並未影響到a*/ /**修改一下a的數組*/ b.key2.push('c') console.log('a.key2',a.key2) /** a.key2:['a','b','c']
a中key2也發生了改變 */
緣由是key1的值屬於基本類型,因此拷貝的時候傳遞的就是該數據段;可是key2的值是堆內存中的對象,因此key2在拷貝的時候傳遞的是指向key2對象的地址,不管複製多少個key2,其值始終是指向父對象的key2對象的內存空間。
四、深拷貝
或許以上並非咱們在實際編碼中想要的結果,咱們不但願父子對象之間產生關聯,那麼這時候能夠用到深拷貝。既然屬性值類型是數組和或對象時只會傳址,那麼咱們就用遞歸來解決這個問題,把父對象中全部屬於對象的屬性類型都遍歷賦給子對象便可。
let a = {
key1: 111 }
a.key2 = ['a','b']
function deepCopy(p,c){ let c2 = c ||{}; for(let i in p ){ if(typeof p[i] === 'object'){ c2[i] = (p[i].constructor === Array) ? [] : {} deepCopy(p[i],c2[i]) }else{ c2[i] = p[i] } } return c2 } let d = {} d = deepCopy(a , d) d.key2.push('d') console.log('a.key2',a.key2) //a.key2: ["a", "b", "c"] console.log('d.key2',d.key2) //d.key2: ["a", "b", "c", "d"]