js 深拷贝和浅拷贝

基本数据类型: String, Boolean, Number, Undefiend, null
引用数据类型:Object, Array, Function, Date, RegExp

基本数据类型和引用类型的区别:

1、保存的位置不同:

  • 基本数据类型保存在栈内存中
    例如 let a = 1


    image.png

    当 let b = a时,栈内存会开辟一个新内存


    image.png

    所以 这时候a和b时完全独立,互不影响的
  • 引用数据类型,名存在栈内存中,值存在堆内存中,但是栈内存会提供一个地址指向堆内存中的值
    例如:

let a = [0,1,2,3,4]
let b = a
a[0] = 1

image.png

image.png

当a[0]=1进行数组修改时,a和b指向同一个地址,所以b也会受到影响,这就是所谓的浅拷贝
image.png

如果时深拷贝的话,就是在堆内存中也开辟了一个新的内存放b的值,那就达到深拷贝的效果了
image.png

为什么基本类型保存在栈中,而引用数据类型保存在堆中?

1、堆比栈大,栈的速度比堆块
2、基本数据类型比较稳定,而且相对来说占用的内存小
3、引用数据类型大小是动态的,而且是无限的,引用值的大小会改变,不能把它放在栈中,否则会降低变量查找的速度,因此放在变量栈空间的值是该对象存储在堆中的地址,地址的大小固定,所以把它存储在栈中对变量性能无任何负面影响
4、堆内存是无序存储,可以根据引用直接获取

Array.prototype.slice(), Array.prototype.concat(), ...(ES6的解构), Object.assign()都是一层拷贝,不算是深拷贝,二级属性不能拷贝出来,第一级的属性确实深拷贝了,拥有了独立的内存,但更深的属性却仍然共用地址。

深拷贝的实现:

1、当对象只有一级属性的时候可以用以下方法进行深拷贝

1) Object.assign()

let obj1 = {name: "victor"}
let obj2 = Object.assign({},obj1)

obj2.name = "john"
console.log('obj1:', obj1) // obj1 { name: 'victor' }
console.log('obj2:', obj2) //  obj2 { name: 'john' }

2)Array.prototype.concat()
3)Array.prototype.slice()
4)ES6 解构

let obj1 = {name: "victor"}
let obj2 = {...obj1}

obj2.name = "john"
console.log('obj1:', obj1) // obj1 { name: 'victor' }
console.log('obj2:', obj2) //  obj2 { name: 'john' }

2、 递归

function deepCopy(obj1){
  let obj2 = Array.isArray(obj1)? []:{}
  if(obj1 && typeof obj1 === "object"){
    for(let i in obj1){
        if(obj1[i] && typeof obj[i] === "object"){
          obj2[i] = deepCopy(obj1[i])
        }else{
        obj2[i] = obj1[i]
        }
      }
    }
  }
  return obj2
} 

3、JSON.stringify() JSON.parse()结合使用

let a = {a:{b:1},c:1}
let b = JSON.parse(JSON.stringify(a))
b.a.b = 2
console.log(a)
console.log(b)
let obj1 = {
   fun:function(){
      alert(123);
   }
}
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun); // function
console.log(typeof obj2.fun); // undefined

缺陷 它会抛弃对象的constructor,深拷贝后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object,这种方法能正确处理的对象只有 Number,String,Boolean,Array,扁平对象,也就是说,只有能转成JSON格式的对象才可以这样用,像function就没办法转成JSON

4、jquery提供的$.extend()可以用来做深拷贝

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

5、lodash提供的 cloneDeep的方法

const _ = require('lodash');
// 官方例子
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

你可能感兴趣的:(js 深拷贝和浅拷贝)