JavaScript深浅拷贝

深浅拷贝

基本类型和引用类型

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

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

image

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

image

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

而若是是在堆中从新分配内存,拥有不一样的地址,可是值是同样的,复制后的对象与原来的对象是彻底隔离,互不影响,为 深拷贝。函数

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

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);

image

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);

image

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

JSON 对象的 parse 和 stringify

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

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);

image

可是该方法也是有局限性的:指针

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

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

固然,也能够利用递归本身封装深度克隆函数,对象

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];
            }
        }
    }
}
相关文章
相关标签/搜索