JavaScript深浅拷贝

Posted y-dt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript深浅拷贝相关的知识,希望对你有一定的参考价值。

深浅拷贝

基本类型和引用类型

  1. ECMAScript 中的变量类型分为两类:
  • 基本类型:undefined,null,布尔值(Boolean),字符串(String),数值(Number)
  • 引用类型: 统称为Object类型,细分的话,有:Object类型,Array类型,Date类型,Function类型等。
  1. 不同类型的存储方式:

基本数据类型 保存在 栈内存,形式如下:栈内存中分别存储着变量的标识符以及变量的值。

技术分享图片

引用类型 保存在 堆内存 中, 栈内存存储的是变量的标识符以及对象在堆内存中的存储地址,当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从对应的堆内存中取得所需的数据。

技术分享图片

对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝。

而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝。

深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。

js的复制方法

slice和concat方法

var a = [[1,2,3],4,5];
var b = a.slice();
console.log(a === b);
a[0][0] = 6;
console.log(a);
console.log(b);

技术分享图片

jQuery中的 extend 复制方法

var obj = {name:‘xixi‘,age:20,company : { name : ‘腾讯‘, address : ‘深圳‘} };
var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_extend);

技术分享图片

Array 的 slice 和 concat 方法 和 jQuery 中的 extend 复制方法,他们都会复制第一层的值,对于 第一层 的值都是 深拷贝,而到 第二层 的时候 Array 的 slice 和 concat 方法就是 复制引用 ,jQuery 中的 extend 复制方法 则 取决于 你的 第一个参数, 也就是是否进行递归复制。

JSON 对象的 parse 和 stringify

JOSN 对象中的 stringify 可以把一个 js 对象序列化为一个 JSON 字符串,parse 可以把 JSON 字符串反序列化为一个 js 对象,这两个方法实现的是深拷贝。

var obj = {name:‘xixi‘,age:20,company : { name : ‘腾讯‘, address : ‘深圳‘} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_json);

技术分享图片

但是该方法也是有局限性的:

  • 会忽略 undefined
  • 不能序列化函数
  • 不能解决循环引用的对象

这个函数可以解决大部分问
题,并且该函数是内置函数中处理深拷贝性能最快的。如果你的数据中含有以上三种情况下,可以使用 lodash 的深拷贝函数。

当然,也可以利用递归自己封装深度克隆函数,

function deepClone(origin, target){
    var target = target || {},
         toStr = Object.prototype.toString,
         arrStr = "[object Array]";

    for(var prop in origin){
        if(origin[prop] !== ‘null‘ && origin.hasOwnProperty(prop)){
            if(typeof(origin[prop]) === ‘object‘) {
                target[prop] = toStr.call(origin[prop]) === arrStr ? [] : {};
                deepClone(origin[prop], target[prop]);
            }else{
                target[prop] = origin[prop];
            }
        }
    }
}

以上是关于JavaScript深浅拷贝的主要内容,如果未能解决你的问题,请参考以下文章

javascript的深浅拷贝

Javascript 对象复制(深浅拷贝)

深浅拷贝

python深浅拷贝

JavaScript深浅拷贝

JavaScript之深浅拷贝