JavaScript:浅拷贝和深拷贝

来源:互联网 发布:seo推荐 编辑:程序博客网 时间:2024/06/05 04:29

阅读本文前,建议先弄明白JS变量中基本类型和引用类型的区别,这里可以参考我的另一篇博客:JavaScript变量和内存(参数按值传递解惑)。


浅拷贝

对于对象的遍历,我们用for…in语句,将一个对象的所有属性方法都拷贝赋值到另一个对象。如果,被拷贝的对象所有的属性都不是引用类型,那么也不会出现什么问题,可是如果被拷贝的对象某些属性是引用类型的,比如是个Object类型或者Array类型的,就会出问题,因为你赋值过去的只是该引用类型属性的的地址,并不是真的开辟空间进行了深度拷贝,所以,这些引用类型的属性是共享的,改变一个,另一个也改变了。


下面的例子,被拷贝的obj都不是引用类型,那么也就没什么问题。


这里写图片描述


但是,下面的例子,有的属性比如family和school是引用类型的属性,那么就出现了共享的问题:


这里写图片描述


深拷贝

深拷贝就是解决浅拷贝共享的问题,如果我们需要独立的拷贝出来的对象,互不影响的,那么我们需要使用深度拷贝来解决这个问题。


考虑到数组和对象的情况,我们需要在遍历的时候对属性的类型进行判断,如果是引用类型,我们就得注意了。



补充:关于callee的用法:

  1. callee返回正在执行的函数本身的引用,它是arguments的一个属性;
  2. 这个属性只有在函数执行的时候才有效;
  3. callee有个属性叫length,可以获得形参的个数,因此可以用来比较形参和实参个数是否一致,即比较arguments.length 是否等于 arguments.callee.length;
  4. 它可以用来递归匿名函数。

function test() {    alert(arguments.callee);}

这里写图片描述


这个用途是递归:

这里写图片描述


其中函数内部包含了对sum自身的引用,函数名仅仅是个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,这时使用callee会是个比较好的方法。

这里写图片描述


考虑到数组和对象的情况,我们需要对传入的数据类型进行判断,通过如下的方法:
这里用到了arguments.callee()方法,它表示的是在哪个函数中执行,就代表哪个函数。在如下的代码中实际指向的是deepClone函数,也就是另一种递归调用的方式。


<!DOCTYPE html><html><head>    <meta charset="utf-8">    <title>LazyLoad</title>    <style type="text/css">    </style></head><body>    <script type="text/javascript">        var obj = {            name: 'guoyu',            age: 28,            sex: 'male',            family: ['father','mather','sister'],            school: {                primary: 'ZGXX',                middle: 'XYYZ',                high: 'HZKJDX'            },            fun: function() {alert('hello');}        };        function isClass(o) {            if (o == null) {return 'Null';}            if (o == undefined) {return 'Undefined';}            //toString返回的:'[object Array]',slice(8,-1)就是Array,返回类型            return Object.prototype.toString.call(o).slice(8, -1);        }        function deepClone(obj) {            var result;            var oClass = isClass(obj);            if (oClass === 'Object') {                result = {};            } else if (oClass === 'Array') {                result = [];            } else {                return obj;            }            for (key in obj) {                var copy = obj[key];                if (isClass(copy) === 'Object') {                    //递归调用                    result[key] = arguments.callee(copy);                    alert(arguments.callee);//指的是deepClone这个函数本身                } else if (isClass(copy) === 'Array') {                    result[key] = arguments.callee(copy);                } else {                    result[key] = obj[key];                }            }            return result;        }        var ret = deepClone(obj);    </script></body></html>