资讯专栏INFORMATION COLUMN

【转】JavaScript 对象的深度克隆

JowayYoung / 1550人阅读

摘要:在聊以下简称深度克隆之前,我们先来了解一下中对象的组成。克隆或者拷贝分为种浅度克隆深度克隆。浅度克隆基本类型为值传递,对象仍为引用传递。

该文转载自http://www.cnblogs.com/zichi/p/4568150.html,有部分修改。

在聊JavaScript(以下简称js)深度克隆之前,我们先来了解一下js中对象的组成。
js 中一切实例皆是对象,具体分为 原始类型合成类型
原始类型 对象指的是 UndefinedNullBooleanNumberString ,按值传递。
合成类型 对象指的是 arrayobject 以及 function ,按址传递,传递的时候是内存中的地址。

克隆或者拷贝分为2种: 浅度克隆深度克隆
浅度克隆 :基本类型为值传递,对象仍为引用传递。
深度克隆 :所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。

又或许你刚听说“深度克隆”这个词,简单来说,就是说有个变量a,a的值是个对象(包括基本数据类型),现在你要创建一个变量b,使得它拥有跟a一样的方法和属性等等。但是a和b之间不能相互影响,即a的值的改变不影响b值的变化。直接赋值可好?

var a = 1;
var b = a;
a = 10;
console.log(b);            // 1
 
var a = "hello";
var b = a;
a = "world";
console.log(b);            // hello
 
var a = true;
var b = a;
a = false;
console.log(b);            // true

实践证明某些 JavaScript 的原始数据类型,如果要克隆直接赋值即可。
关于 function 的深度复制:查阅了一些资料, function 的深度复制似乎和原始数据类型的深度复制一样。

var a = function () {
    console.log(1);
};
var b = a;
a = function () {
    console.log(2);
};
b();                    // 1

本来我也是这么认为的,直到文章下出现了评论。思考后我觉得 function 和普通的对象一样,只是我们在平常应用中习惯了整体的重新赋值,导致它在深度复制中的表现和原始类型一致:

var a = function () {
    console.log(1);
};
a.tmp = 10;
var b = a;
a.tmp = 20;
console.log(b.tmp);        // 20

于是乎对于 function 类型的深度克隆,直接赋值似乎并不应该是一种最好的方法(尽管实际应用中足矣)。

但是对象呢?

var a = [0,1,2,3];
var b = a;
a.push(4);
console.log(b);            // [0, 1, 2, 3, 4]

显然与预期不符,为什么会这样?因为原始数据类型储存的是对象的实际数据,而对象类型存储的是对象的引用地址。上面的例子呢也就是说a和b对象引用了同一个地址,无论改变a还是改变b,其实根本操作是一样的,都是对那块空间地址中的值的改变。

于是我们知道了,对于基本的对象来说,不能只能用 “ = ” 赋值,思索后写下如下代码:

// 判断arr是否为一个数组,返回一个bool值
function isArray (arr) {
    return Object.prototype.toString.call(arr) === "[object Array]";  
}
// 深度克隆
function deepClone (obj) {  
    if(typeof obj !== "object" && typeof obj !== "function") {
        return obj;        //原始类型直接返回
    }
    var o = isArray(obj) ? [] : {}; 
    for(i in obj) {  
        if(obj.hasOwnProperty(i)){ 
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i]; 
        } 
    } 
    return o;
}

注意代码中判断数组的时候用的不是 obj instanceof Array ,这是因为该方法存在一些小问题,详情见 http://www.nowamagic.net/librarys/veda/detail/1250

用一些代码来测试下:

// 测试用例:
var srcObj = {
    a: 1,
    b: {
        b1: ["hello", "hi"],
        b2: "JavaScript"
    }
};
var abObj = srcObj;
var tarObj = cloneObject(srcObj);

srcObj.a = 2;
srcObj.b.b1[0] = "Hello";

console.log(abObj.a);
console.log(abObj.b.b1[0]);

console.log(tarObj.a);      // 1
console.log(tarObj.b.b1[0]);    // "hello"

似乎可以解决一般的对象(包括 Array )的深度克隆了,或许这儿会有疑问,new String(..) 这类的也是对象啊,可是这样写你克隆不了啊…但是楼主觉得深度克隆的考点不在这里,可能在于:

原始数据类型的直接赋值

function的exception

对象的深度克隆中Array类型的判断

克隆函数的递归调用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78783.html

相关文章

  • js对象详解(JavaScript对象深度剖析,深度理解js对象)

    摘要:对象详解对象深度剖析,深度理解对象这算是酝酿很久的一篇文章了。用空构造函数设置类名每个对象都共享相同属性每个对象共享一个方法版本,省内存。 js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了。 JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕。 平时发的文章基本都是开发中遇到的问题和对...

    CatalpaFlat 评论0 收藏0
  • 如何深度克隆一个对象

    摘要:如何深度克隆一个对象在我们日常工作中经常会遇到需要去克隆一个对象比如多个地方用到的公共的图表基本参数的配置相信很多人会想到用和方法去克隆一个对象,这个可以明确告诉大家这些都是些不靠谱的浅度克隆。 如何深度克隆一个对象 在我们日常工作中经常会遇到需要去克隆一个对象比如多个地方用到的公共的图表基本参数的配置 相信很多人会想到用 Object.assign, JSON.stringify 和...

    TIGERB 评论0 收藏0
  • 浅拷贝与深拷贝

    摘要:二浅拷贝与深拷贝深拷贝和浅拷贝是只针对和这样的引用数据类型的。浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。对于字符串数字及布尔值来说不是或者对象,会拷贝这些值到新的数组里。 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。 基本数据类型的特点:直...

    hzc 评论0 收藏0
  • 浅拷贝与深拷贝

    摘要:二浅拷贝与深拷贝深拷贝和浅拷贝是只针对和这样的引用数据类型的。浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。对于字符串数字及布尔值来说不是或者对象,会拷贝这些值到新的数组里。 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。 基本数据类型的特点:直...

    史占广 评论0 收藏0
  • JavaScript 深拷贝性能分析

    摘要:它接受任意数量的源对象,枚举它们的所有属性并分配给。所以现在怎么办有几种方法可以创建一个对象的深拷贝。为了防止发生任何意外,请使用而不是。我想测量哪种方法是最高性能的。图表以下是,和中不同技术的性能。 原文:Deep-copying in JavaScript - DasSur.ma 如何在 JavaScript 中拷贝一个对象?对于这个很简单的问题,但是答案却不简单。 引用传值 在...

    MyFaith 评论0 收藏0

发表评论

0条评论

JowayYoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<