欢迎大家关注我的 github
基本类型和引用类型
基本类型:存放在栈内存中的数据段,因为是按值存储,可以直接访问和修改
引用类型:存放在堆内存中的对象。在栈内存中变量保存的是一个指针,指向对应在堆内存中的地址。当访问引用类型的时候,要先从栈中取出该对象的地址指针,然后再从堆内存中取得所需的数据。
传值和传址
基本类型是按值存放,可以直接访问是传值
引用类型是在栈中存放的是地址,需要按照地址再去访问相应的值是传址
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的地址复制一份给b,此时a和b访问的都是同一个地址的对象,所以修改b[4]会直接修改堆内存中的对象的值,a和b都同时访问该值,a和b就产生了关联。如何解除关联,可以看c是通过直接赋值堆内存中的对象的值(一个基本类型),这就是按值传递了,所以c不会和a、b建立联系
所以简单的说就是,深拷贝一定都是按值传递,浅拷贝一定有按址传递
浅拷贝
var a = {
key1:"11111"
}
function Copy(p) {
var c = {}; //(在堆内存中新生成一个空对象,这样来杜绝关联)
for (var i in p) {
c[i] = p[i];
}
return c;
}
a.key2 = ['小辉','小辉'];
var b = Copy(a);
b.key3 = '33333';
alert(b.key1); //1111111
alert(b.key3); //33333
alert(a.key3); //undefined

由于a.key2是个引用类型,所以copy的时候a.key2是按址传递的,就会导致修改a.key2的值时,b.key2的值也会变化,因为是按址传递的。因为a和b会有关联,所以说这次拷贝是一次浅拷贝
深拷贝
将刚才的代码改成这样:
var a = {
key1:"11111"
}
function Copy(p) {
var c = {}; //(在堆内存中新生成一个空对象,这样来杜绝关联)
for (var i in p) {
c[i] = p[i];
}
return c;
}
var b = Copy(a);
b.key1 = '33333';
alert(a.key1); //1111111
alert(b.key1); //33333

这次拷贝因为copy的是基本类型,是按值传递,所以这是深拷贝
此时的情况是知道当前对象的结构,如果不知道当前对象的结构如何进行深拷贝呢?可以通过递归进行深拷贝
function copy(a, b) {
var c = c || {}
for(var i in a) {
if(typeof a[i] == 'object') {
if(a[i].constructor == Array) {
copy(a[i], c[i])
} else if(a[i].constructor == Object) {
copy(a[i], c[i])
}
} else {
c[i] = a[i]
}
}
return c
}
var a = {
key1: '11111',
key2: [1,2,3,4,5]
}
var b = copy(a, b)
b.key2 = [2,2,2,2,2]
alert(a.key2) // 1,2,3,4,5
alert(b.key2) // 2,2,2,2,2
a和b之间copy时都是按值传递,所以a和b没有关联,所以这是一次深拷贝


参考资料:
http://www.cnblogs.com/lsgxeva/p/7985583.html