JavaScript中的数据类型次要分为根本数据类型援用数据类型
常见根本数据类型次要有:undefined, null, 布尔值, 字符串和数值;
援用类型次要是对象(Object)。
要探讨对象的深浅拷贝问题,首先要理解下JS中的堆内存和栈内存的。

栈内存(stack)和堆内存(heap)

栈内存中变量个别都是已知大小或者范畴有下限的,可看做简略存储,给人整齐划一的感觉。次要用于存储各种根本类型的变量,包含Boolean、Number、String、Undefined、Null,以及对象变量的指针。
而堆内存贮存的数据大小,往往都是未知的。对象自身是贮存在堆内存中的。

对堆栈内存数据有点理解之后咱们持续想,当初有obj1这么一个对象,咱们心愿依据obj1拷贝出一个对象obj2来,当初咱们有三大类形式:

  1. 间接赋值
  2. 浅拷贝
  3. 深拷贝

赋值

间接将obj1赋值给obj2,其实赋予的值是obj1的指针,此时的赋值,只是“赋址”。也就是obj1和obj2在栈内存中的值都是obj1的指针,都指向堆内存中的obj1。所以当咱们扭转obj1或obj2的任何一个的数据时,另一个都会扭转(两者其实是同一对象)。

var obj1 = {    name: "greennn",    age: 25,    bestfriend: {        name: "xiaoming",        age: 23    }};var obj2  = obj1;obj2.age = 20;obj1.bestfriend.name = "xiaohong";console.log( obj1.age );   // 20console.log( obj2.bestfriend.name);  //"xiaohong"console.log( obj1 === obj2 );  // true 

浅拷贝

浅拷贝会将对象的第一层属性值独立的拷贝给新对象。
浅拷贝能够通过创立一个新的空对象,for...in遍历现有对象的属性增加给新对象;代码更简洁的形式是Object.assign()办法。也能够应用第三方库,如【Underscore】_.clone()等。
咱们先看看第一种形式封装的写法。

function shallowCopy( obj ) {    let copy = Array.isArray(obj) ? [] : {};    for (let i in obj) {        copy[i] = obj[i];    }    return copy;}var obj2 = shallowCopy( obj1 );... 

这里咱们用Object.assign()办法实现浅拷贝,展现后果。
当对象只有一层属性时:

var obj1 = {    name: "greennn",    age: 25};var obj2  = Object.assign( {}, obj1 );obj2.age = 20;console.log( obj1.age )   // 25console.log( obj1 === obj2 )  // false 

当初obj1和obj2看上去就是两个独立的对象了,的确起到了“拷贝”的成果。但浅拷贝的“浅”字通知咱们这里必定有陷阱,接下来咱们看看对象的某个属性是对象时的状况。

var obj1 = {    name: "greennn",    age: 25,    bestfriend: {        name: "xiaoming",        age: 23    }};var obj2  = Object.assign( {}, obj1 );obj2.age = 20;obj1.bestfriend.name = "xiaoding";console.log( obj1.age )   // 25console.log( obj2.bestfriend.name ); // "xiaoding"console.log( obj1 === obj2 )  // false 

上例就能看进去,浅拷贝只是复制了一层属性,而且当原对象有多层属性时,第一层的某个属性prop1的值指向一个对象时,理论记录的是指针,复制的值也是该属性值对象的指针,即新旧两个对象的prop1属性记录都是指向同一对象的指针。看上面示意图会更分明一些:

深拷贝

深拷贝是指将每一层的属性都独立拷贝给新对象,实现两个对象的齐全隔离。
深拷贝的实现有以下几个形式:

  1. 通过JSON转化
    这个形式代码简洁,但它存在的问题是只能正确处理 Number, String, Boolean, Array,等扁平对象,即那些可能被 json 间接示意的数据结构。无奈复制对象中的函数,会疏忽对象中的undefined。
function jsonCopy(obj) {    return JSON.parse(JSON.stringify(obj));}var obj2 = jsonCopy({ a:1 }); 
  1. for···in循环加递归
    只是一段简略的示例,性能上其实和下面的JSON一样,在一些非凡状况下会有问题,为了防止踩坑倡议一看而过。
function deepCopy(obj) {    let copy = Array.isArray(obj) ? [] : {};    for (let i in obj) {        // 遍历时过滤掉原型链上的属性        if (obj.hasOwnProperty(i)) {            // 属性是对象时递归解决            copy[i] = typeof obj[i] === "object" ? deepCopy(obj[i]) : obj[i];        }    }    return copy;} 
  1. lodash _.cloneDeep()
    本着不要反复造轮子的准则(除非你能造的比人家好),还是倡议间接应用第三方库lodash的办法。lodash提供的复制办法有两个,_.clone()和_.cloneDeep()。其中_.clone(obj, true)等价于_.cloneDeep(obj)。
var _ = require("lodash");var obj1 = {    name: "greennn",    age: 25,    bestfriend: {        name: "xiaoming",        age: 23    }};var obj2 = _.cloneDeep( obj1 );obj2.age = 20;obj1.bestfriend.name = "xiaoding";console.log( obj1.age )   // 25console.log( obj2.bestfriend.name ); // "xiaoming"console.log( obj1 === obj2 )  // false 

能够看出,通过深拷贝之后,obj1 和 obj2曾经齐全独立,互不干涉了。