js浅拷贝与深拷贝方法

js有五种基本数据类型,string,number,boolean,null,undefind。这五种类型的赋值,就是值传递。特殊类型对象的赋值是将对象地址的引用赋值。这时候修改对象中的属性或者值,会致使全部引用这个对象的值改变。若是想要真的复制一个新的对象,而不是复制对象的引用,就要用到对象的深拷贝。jquery

浅拷贝实现方式

1.‘=’赋值。

很少说,最基础的赋值方式,只是将对象的引用赋值。json

2.Object.assign()

Object.assign是ES6的新函数。Object.assign() 方法能够把任意多个的源对象自身的可枚举属性拷贝给目标对象,而后返回目标对象。可是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象自己。数据结构

Object.assign(target, ...sources)

参数:
target:目标对象。
sources:任意多个源对象。
返回值:目标对象会被返回。函数

var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);

initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"

须要注意的是:
Object.assign()能够处理一层的深度拷贝,以下:ui

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }

深拷贝

1.手动复制

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }

2.JSON作字符串转换

用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。code

var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false

这样作是真正的Deep Copy,这种方法简单易用。对象

可是这种方法也有很多坏处,譬如它会抛弃对象的constructor。也就是深拷贝以后,无论这个对象原来的构造函数是什么,在深拷贝以后都会变成Object。递归

这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些可以被 json 直接表示的数据结构。RegExp对象是没法经过这种方式深拷贝。字符串

也就是说,只有能够转成JSON格式的对象才能够这样用,像function没办法转成JSON。get

var obj1 = { fun: function(){ console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);
// 'function'
console.log(typeof obj2.fun);
// 'undefined' <-- 没复制

3.递归拷贝

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象致使死循环,如initalObj.a = initalObj的状况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : {};            
      arguments.callee(prop, obj[i]);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);

4.使用Object.create()方法

直接使用var newObj = Object.create(oldObj),能够达到深拷贝的效果。

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象致使死循环,如initalObj.a = initalObj的状况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

5.jquery

jquery 有提供一个$.extend能够用来作 Deep Copy。

var $ = require('jquery');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
// false

6.第三方函数

还有一些其它的第三方函数库有深拷贝function,如lodash。

相关文章
相关标签/搜索