拷贝应该对于大家来说挺熟悉的吧,我们简单的ctrl+C和ctrl+V,复制粘贴,拷贝就是这个意思,将一个目标数据复制一份,形成两个个体。
我们将一个基本数据类型(数值、字符型)的变量赋值给另一个变量,就可以得到两个值相同的变量,改变其中一个变量的值,不会影响另一个变量的值。
但是,如果操作的目标是复合数据类型(如数组、对象),则会出现两个变量指向同一个对象的情况,如果改变其中一个对象的成员,另一个对象也会发生改变。
具体示例如下:
代码:
script>
var p1 ={name:'yan',age:21}
var p2 =p1;
p2.name ='long';
console.log(p1);
console.log(p2);
console.log(p1===p2);
</script>
运行结果截图:
在网页中,鼠标右键,单击“检查”,进入控制台查看。
从运行结果可以看出,在将变量p1赋值给p2后,更改p2的成员,p1的成员也会发生改变。这种情况在JavaScript中称之为“浅拷贝”。可以这么理解,将上述代码中的对象“{name:’long’,age:21}”想象成一个文件夹,该文件夹中保存了name和age两个文件,而变量p1是链接到这个文件夹的快捷方式。在执行“var p2=p1;”操作时,是将快捷方式复制了一份,此时两个快捷方式指向了同个文件夹,而不是对文件夹进行复制操作。
其存在的优点:
在实际开发中,浅拷贝可以节省内存开销。因为一个对象可以保存大量的数据,其占用的内存会比基本数据类型高。如果没有浅拷贝机制,在将对象作为函数参数传递时,函数内部的实参就会创建对象的副本,多占用一份内存空间,尤其是进行函数嵌套调用或递归操作时,占用空间会越来越多。
与浅拷贝相对应的就是深拷贝,即真正创建一个对象的副本,也就是我们想象中的“CV”。
代码例子如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>深拷贝</title>
</head>
<body>
<script>
function deepCopy(obj){
var o ={};
for (var k in obj){
o[k] = (typeof obj[k] === 'object') ? deepCopy(obj[k]) :obj[k];
}
return o;
}
var p1 ={name:'jim',subject:{name:['Html','CSS']} };
var p2 =deepCopy(p1);
p2.subject.name[0] = 'JavaScript';
console.log(p1.subject.name[0]);
console.log(p2.subject.name[0]);
console.log(p1 === p2);
</script>
</body>
</html>
运行结果截图:
在网页中,鼠标右键,单击“检查”,进入控制台查看。
在上述代码中,var o ={};创建了一个新对象o用来保存成员,在for循环语句中遍历了obj对象的每一个成员,在遍历时,通过“o[k] = obj[k]”实现成员的复制。由于传入的对象obj的成员有可能还是一个对象,所以通过typeof来进行判断,如果typeof检测的类型为object(数组、对象的类型都是object)则递归调用deepCopy()函数,进行完整的复制。
从结果来看,p1和p2是两个不同的对象,在修改p2的成员后不影响p1的成员。