一、栈(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"]