资讯专栏INFORMATION COLUMN

javascript深拷贝(deepClone)

hatlonely / 1034人阅读

摘要:实现实现一个深拷贝函数,就不得不说的数值类型。类型来看下面代码,结果会返回啥呢答案是有时候保存了元素,一不小心进行深拷贝,上面的深拷贝函数就缺少了对元素的判断。在不同的场景下,要根据业务场景,判断是否需要使用深拷贝。

javascript深拷贝是初学者甚至有经验的开发着,都会经常遇到问题,并不能很好的理解javascript的深拷贝。

深拷贝(deepClone)?

与深拷贝相对的就是浅拷贝,很多初学者在接触这个感念的时候,是很懵逼的。

为啥要用深拷贝?

在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性。
看一个具体的例子

// 给test赋值了一个对象
var test = {
    a: "a",
    b: "b"
};

// 将test赋值给test2
// 此时test和test2是共享了同一块内存对象,这也就是浅拷贝
var test2 = test;

test2.a = "a2";

test.a === "a2"// 为true

图解:

这下就很好理解为什么引用值类型数据相互影响问题。

实现

实现一个深拷贝函数,就不得不说javascript的数值类型。

判断javascript类型

javascript中有以下基本类型

类型 描述
undefined undefined类型只有一个值undefined,它是变量未被赋值时的值
null null类型也只有一个值null, 它是一个空的对象引用
Boolean Boolean有两种取值true和false
String 它表示文本信息
Number 它表示数字信息
Object 它是一系列属性的无序集合, 包括函数Function和数组Array

使用typeof是无法判断function和array的,这里使用Object.prototype.toString方法。
[默认情况下,每个对象都会从Object上继承到toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的toString()方法时会返回"[object type]",这里的字符串type表示了一个对象类型][1]

function type(obj) {
    var toString = Object.prototype.toString;
    var map = {
        "[object Boolean]"  : "boolean", 
        "[object Number]"   : "number", 
        "[object String]"   : "string", 
        "[object Function]" : "function", 
        "[object Array]"    : "array", 
        "[object Date]"     : "date", 
        "[object RegExp]"   : "regExp", 
        "[object Undefined]": "undefined",
        "[object Null]"     : "null", 
        "[object Object]"   : "object"
    };
    return map[toString.call(obj)];
}
实现deepClone

对于非引用值类型的数值,直接赋值,而对于引用值类型(object)还需要再次遍历,递归赋值。

function deepClone(data) {
    var t = type(data), o, i, ni;
    
    if(t === "array") {
        o = [];
    }else if( t === "object") {
        o = {};
    }else {
        return data;
    }
    
    if(t === "array") {
        for (i = 0, ni = data.length; i < ni; i++) {
            o.push(deepClone(data[i]));
        }
        return o;
    }else if( t === "object") {
        for( i in data) {
            o[i] = deepClone(data[i]);
        }
        return o;
    }
}

这里有个点大家要注意下,对于function类型,博主这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。

但是function类型要怎么拷贝呢?

其实博主只想到了用new来操作一下,但是function就会执行一遍,不敢想象会有什么执行结果哦!o(╯□╰)o!其它暂时还没有什么好的想法,欢迎大家指导哦!

到这里差不多也就实现完了深拷贝,又有人觉的怎么没有实现浅拷贝呢?

浅拷贝?

对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!(。﹏。*)

如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行CURD操作。

到这里估计就差不多了,但是作为一个前端,不仅仅考虑javascript本身,还得考虑到dom、浏览器等。

Element类型

来看下面代码,结果会返回啥呢?

Object.prototype.toString.call(document.getElementsByTagName("div")[0])

答案是[object HTMLDivElement]

有时候保存了dom元素, 一不小心进行深拷贝,上面的深拷贝函数就缺少了对Element元素的判断。而判断Element元素要使用instanceof来判断。因为对于不同的标签,tostring会返回对应不同的标签的构造函数。

function type(obj) {
    var toString = Object.prototype.toString;
    var map = {
        "[object Boolean]"  : "boolean", 
        "[object Number]"   : "number", 
        "[object String]"   : "string", 
        "[object Function]" : "function", 
        "[object Array]"    : "array", 
        "[object Date]"     : "date", 
        "[object RegExp]"   : "regExp", 
        "[object Undefined]": "undefined",
        "[object Null]"     : "null", 
        "[object Object]"   : "object"
    };
    if(obj instanceof Element) {
        return "element";
    }
    return map[toString.call(obj)];
}
其它方式?

jquery的实现
详见https://github.com/jquery/jqu...

underscore的实现
详见https://github.com/jashkenas/...

lodash的实现
详见https://github.com/lodash/lod...

JSON实现
先通过JSON.stringify一下,然后再JSON.parse一下,就能实现深拷贝。但是数据类型只支持基本数值类型。

var obj = {
    a: "a",    
    b: function(){console.log("b")}
}

//在JSON.stringify的时候就会把function给过滤了。

JSON.stringify(obj)// "{"a":"a"}"
小结

这里大概总结了一下深拷贝,以及怎么实现一个深拷贝。在不同的场景下,要根据业务场景,判断是否需要使用深拷贝。
原文链接 http://xiaoqiang730730.github...

参考文献

winter-JavaScript中的类型
http://www.cnblogs.com/winter...

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

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

相关文章

  • JavaScript中浅拷贝拷贝的区别和实现

    摘要:要理解中浅拷贝和深拷贝的区别,首先要明白的数据类型有两种数据类型,基础数据类型和引用数据类型基础数据类型保存在栈内存中的简单数据段,有,,,,引用数据类型,对象,保存在堆内存空间中存放在栈内存中与变量名与内存地址存储在栈内存中,与作为对象存 要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型 JavaScript有两种数据类型,基础数据类型和引...

    wenshi11019 评论0 收藏0
  • JavaScript中的浅拷贝拷贝

    摘要:在中可以通过添加一个参数来实现递归,调用就可以实现一个深拷贝。利用序列化实现一个深拷贝 在JavaScript中,对于Object和Array这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。 这种拷贝分为两种情况:拷贝引用和拷贝实例,也就是我们说的浅拷贝和深拷贝 浅拷贝(shallow...

    ernest.wang 评论0 收藏0
  • 浅谈JavaScript拷贝实现的方法

    摘要:相信人很多学习的过程中都踩了深拷贝和浅拷贝的坑,深拷贝和浅拷贝的区别我就不再赘述了,今天我来写一下我自己实现深拷贝的各种方法。中的深拷贝也是用类似方法实现。 相信人很多学习js的过程中都踩了深拷贝和浅拷贝的坑,深拷贝和浅拷贝的区别我就不再赘述了,今天我来写一下我自己实现深拷贝的各种方法。 比较简单的拷贝方式可以借用浏览器的Json对象去实现,先把对象转化为json字符串,在解析回对...

    Vicky 评论0 收藏0
  • 复习Javascript专题(四):js中的拷贝

    摘要:基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对,这类引用类型数据。它会抛弃对象的。另外,查资料过程中还看到这么一个词结构化克隆算法还有这一篇资料也有参考,也写得比较详细了的深浅拷贝 基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对Object,Array这类引用类型数据。 浅拷贝对于字符串来说,是值的复制,而对于对象来说则是对对象地址的复制;而深拷贝的话,它不...

    MobService 评论0 收藏0
  • 拷贝

    摘要:深复制实现代码如下第一种方法通过递归解析解决第二种方法通过解析解决作者六师兄链接原生深拷贝的实现处理未输入新对象的情况通过方法构造新的对象 深浅拷贝针对的是 对象类型,如果是字符串的数组用[...arr],还是不会影响 要区分针对数组的深浅拷贝(默认情况为里面没有对象的数组),与针对对象的深浅拷贝 JavaScript数组深拷贝和浅拷贝的两种方法 let a1 = [1, 2]; ...

    Karrdy 评论0 收藏0

发表评论

0条评论

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