JavaScript:浅拷贝和深拷贝

阅读本文前,建议先弄明白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>
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值