很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现。

在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用访问这两个概念。

按值访问是针对基本类型(string、number、boolean、null、undefined)。基本类型以值的形式被存放在栈内存中,我们通过变量操作的是栈内存中实际的值。

按引用访问时针对引用类型(Object、Array、Date、RegExp、Function)。引用类型以对象的形式被存放在堆内存中,我们通过变量操作的堆内存中对象的引用,也就是说,变量中保存的是一个指针,指向内存中的某个位置。

--------------------------分割线--------------------------

浅拷贝与深拷贝的区别是针对引用类型而言的,浅拷贝只是拷贝了对象表面上的一层,而深拷贝是拷贝了对象的所有层级。

那这两种方式,区别在哪里呢?

举个例子:

var arr = ['a', 'b'];
var newArr = arr;  // newArr拷贝了arr

console.log(newArr);  // ['a', 'b']

arr.push('c');

console.log(newArr);  //['a', 'b', 'c']

以上代码是一个简单的浅拷贝。

由于arr是一个数组,数组内部保存了两个string类型的值。newArr通过直接赋值得到该数组的引用,此时newArr和arr所指向的是内存中的同一个位置,所以arr的操作反应到内存中数组的改变,也就导致了newArr的改变。

下面来看看深拷贝:

var arr = ['a', 'b'];
var newArr = [];

newArr[0] = arr[0];
newArr[1] = arr[1];

console.log(newArr);  // ['a', 'b']

arr.push('c');

console.log(newArr);  //['a', 'b']

以上代码是一个简单的深拷贝。

我们发现此时,arr的改变并没有影响到newArr,原因就在于,这次我们是先定义了一个空数组newArr(在内存中开辟了新的位置),此时newArr与arr所指向的是内存中不同的位置,然后我们对数组中的string类型的值进行赋值操作,得到了最后的newArr。

那么,我们现实中遇到的拷贝问题不会是这简单的数组,可能会像这样:

var person1 = {
    name: 'Mike',
    age: 5,
    friends: [ 'Jack', 'Candy' ]
};

对于这个例子,如果我们想实现深拷贝,就需要遍历person1的所有属性。由于name、age是基本类型,所以直接赋值没有问题,但是friends是数组,也就是引用类型,那么我们也需要遍历friends,万一friends数组的某个元素是引用类型,那么继续,以此类推......

所以,实现深拷贝并不是那么容易的,下面我们来看看jQuery中是如何处理的。

// 这是一个用来扩展jQuery的方法,jQuery.extend([boolean], arg1, arg2, ...)
// 第一个参数可选,表示进行浅拷贝或深拷贝,默认false
// 第二个参数是拷贝后的存放目标(后面简称拷贝目标)
// 第三个及以后的参数都是拷贝对象(后面简称拷贝对象)

jQuery.extend = jQuery.fn.extend = function () {
        var options, name, src, copy, copyIsArray, clone,
            target = arguments[0] || {},
            i = 1,
            length = arguments.length,
            deep = false;

        if (typeof target === "boolean") {
            deep = target;

            target = arguments[i] || {};
            i++;
        }

        if (typeof target !== "object" && !jQuery.isFunction(target)) {
            target = {};
        }

        if (i === length) {
            target = this;
            i--;
        }

        // 以下开始重点
        // 遍历arg2, arg3, ...

        for (; i < length; i++) {

            // 如果拷贝对象不是null,并存放到变量options中
            if ((options = arguments[i]) != null) {

                // 遍历拷贝对象的属性
                for (name in options) {
                    src = target[name]; // 拷贝目标中的相应属性值
                    copy = options[name]; // 拷贝对象中的相应属性值

                    // 防止循环引用
                    if (target === copy) {
                        continue;
                    }

                    // 如果deep(布尔参数)为true,也就是要进行深拷贝,并且拷贝对象中该属性值是数组或者对象
                    if (deep && copy && (jQuery.isPlainObject(copy) ||
                        (copyIsArray = Array.isArray(copy)))) {

                        if (copyIsArray) { // 如果该属性值是数组
                            copyIsArray = false;
                            clone = src && Array.isArray(src) ? src : []; // 拷贝目标中该属性值

                        } else { // 如果该属性值是对象
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }

                        // 以该属性值作为拷贝对象,递归调用jQuery.extend()
                        target[name] = jQuery.extend(deep, clone, copy);

                    // 否则浅拷贝
                    } else if (copy !== undefined) {
                        target[name] = copy; // 直接赋值
                    }
                }
            }
        }

        // 返回最终的拷贝目标
        return target;
    };

欢迎补充和指正

Javascript中的浅拷贝和深拷贝的更多相关文章

  1. javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)

    作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  2. javascript中的浅拷贝和深拷贝 分类: JavaScript 2015-05-07 15:29 831人阅读 评论(1) 收藏

    1.js对象浅拷贝 简单的赋值就是浅拷贝.因为对象和数组在赋值的时候都是引用传递.赋值的时候只是传递一个指针. 看下面的实例代码: var a = [1,2,3]; var b =a ; var te ...

  3. 【转】JAVA中的浅拷贝和深拷贝

    原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...

  4. javascript中的堆栈、深拷贝和浅拷贝、闭包

    堆栈 在javascript中,堆内存是用来存放引用类型的空间环境 而栈内存,是存储基本类型和指定代码的环境 在对象中的属性名具有唯一性,数字属性名=字符串属性名,但是在测试的时候你会发现,好像所有属 ...

  5. javascript中的浅拷贝ShallowCopy与深拷贝DeepCopy

    拷贝,在js中,分为浅拷贝和深拷贝.这两者是如何区分的呢?又是如何实现的呢? 深浅拷贝的区分 首先说下,在js中,分为基础数据类型和复杂数据类型, 基础数据类型:Undefined.Null.Bool ...

  6. js中的浅拷贝和深拷贝

    说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...

  7. 浅谈JS中的浅拷贝与深拷贝

    前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙地运 ...

  8. C# 中的浅拷贝与深拷贝

    Ø  简介 在 C# 中分为两种数据类型,值类型和引用类型.我们知道,值类型之间赋值是直接将值赋值给另一个变量,两个变量值的改变都互不影响:而引用类型赋值则是将引用赋值给另一个变量,其中一个变量中的成 ...

  9. Javascript/js 的浅拷贝与深拷贝(复制)学习随笔

    js变量的数据类型值分基本类型值和引用类型值. 在ES6(ECMAScript6)以前,基本数据类型包括String.Number.Boolean.Undefined.Null. 基本类型值的复制(拷 ...

随机推荐

  1. Java类加载机制、类加载器和反射机制-思维导图

    参考文献: 1. <深入理解JVM虚拟机>

  2. IDEA 单元测试testng入门及testng.xml

    直接进入正题: 1.TestNG的运行方式如下: With a testng.xml file 直接run as test suite With ant 使用ant From the command ...

  3. phpstudy:80端口被占用解决方案总结

    一开始因为要安装新的软件,同时也由于一直电脑很卡,所以直接重装系统,从WIN8变成WIN10,然后不知道为什么,phpstudy里面80端口被占用了!被占用了!现在找到了两种方法解决! 第一种 该端口 ...

  4. css阴影,边框,渐变,背景

    一.box-shadow: 参数1,参数2 阴影位置偏移量 参数3 模糊半径 参数4 扩展半径 负数 0 默认值 正数 参数5 阴影的颜色 参数6 设置内阴影 inset 默认是外阴影 多个阴影使用, ...

  5. PowerShell 脚本中的密码

    引言 笔者在<PowerShell 远程执行任务>一文中提到了在脚本中使用用户名和密码的基本方式: $Username = 'xxxx' $Password = 'yyyy' $Pass ...

  6. iOS 配置

    1.git的配置 使用Github,也许大家觉得比较麻烦的就是在每次push的时候,都需要输入用户名和密码.如果使用SSH,就可以记住用户名,并创建属于自己的密码来保证安全操作,还有神奇的一招可以“不 ...

  7. Git时光机穿梭之工作区和暂存区

    Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念. 先来看名词解释. 工作区(Working Directory) 就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工 ...

  8. centos7下nginx安装

    http://www.linuxidc.com/Linux/2016-09/134907.htm 安装所需环境 Nginx 是 C语言 开发,建议在 Linux 上运行,当然,也可以安装 Window ...

  9. echarts之词云随机颜色的配置

    echarts中的词云字体产生随机颜色,最主演的是要引入worldcloud.js,另外还要有jquery.js文件与echarts.js文件的引入,通过配置即可实现词云随机颜色的产生.下面为大家介绍 ...

  10. KMS注册

    --KMS注册 -------------2014/03/25 --Read this First http://social.technet.microsoft.com/wiki/contents/ ...