深拷贝、浅拷贝的实现

深拷贝、浅拷贝实现

JavaScript的数据类型分为基本数据类型和引用数据类型。

5种基本数据类型Undefined、Null、Boolean、Number 和 String,变量是直接按值存放的,存放在栈内存中的简单数据段,可以直接访问。

检测对象的判断

function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}

不太适合本文,本文包括数组

[]和{} ,null的都是object

可以用

function isObject(obj) {
    return typeof obj === 'object' && obj != null;
}

也可以用如果值是对象用下面

source[keys] && typeof source[keys] === 'object'

对于基本数据类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用数据类型而言的。

浅拷贝的意思就是只复制引用,而未复制真正的值。

const originArray = ['火影忍着','海贼王','名侦探柯南'];
const originObj = {
  name: 'sophia',
  age: 18,
  hobby: ['swimming', 'shopping', [1, 2, [ 'a', 'b']]],
  book: {
      title: "Node.js实战",
      price: "69",
      content: ['1章', '2章']
  },
  print: function(){
      console.log('--print-->', this.name)
  },
  t1: undefined,
  t2: null,
  t3: 123
};

一、浅拷贝的实现方式

1、模拟一个浅拷贝函数

遍历对象,然后把属性和属性值都放在一个新的对象

var shallowCopy = function(obj) {
    // 只拷贝对象
    if (typeof obj !== 'object') return;
    // 根据obj的类型判断是新建一个数组还是对象
    var newObj = obj instanceof Array ? [] : {};
    // 遍历obj,并且判断是obj的属性才拷贝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

二、深拷贝实现

目前实现深拷贝的方法不多,主要是两种:

1、利用 JSON 对象中的 parse 和 stringify

利用递归来实现每一层都重新创建对象并赋值

const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false

cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

但是有缺陷

undefined、function、symbol 会在转换过程中被忽略,就是说如果对象中含有一个函数时(很常见),就不能用这个方法进行深拷贝

const originObj = {
  name:'axuebin',
  sayHello:function(){
    console.log('Hello World');
  }
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj); // {name: "axuebin"}

另外数组有两个方法 concat 和 slice 是可以实现对原数组的拷贝的,这两个方法都不会修改原数组,而是返回一个修改后的新数组,同时,ES6 中 引入了 Object.assgn 方法和 ... 展开运算符也能实现对对象的拷贝。但他们对于多层数组不适用,只拷贝第一层数组

2、递归的方法

递归的思想就很简单了,就是对每一层的数据都实现一次 创建对象->对象赋值 的操作,简单粗暴上代码



function deepClone(source){
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in source){ // 遍历目标
    if(source.hasOwnProperty(keys)){
      if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = source[keys].constructor === Array ? [] : {};
        targetObj[keys] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    } 
  }
  return targetObj;
}

 

 

posted @ 2020-04-30 01:32  pikachuWorld  阅读(430)  评论(2编辑  收藏  举报