js克隆

114 阅读3分钟

浅克隆

基础数据类型

数据类型的特性,在赋值的时候,基本数据类型和引用类型是不一样的。

   // 基本数据类型
   var a = '我是变量a的值';
   var b = a;

   console.log(a);    // 我是变量a的值
   console.log(b);   // 我是变量a的值

   b = '我是变量b的值';

   console.log(a);   // 我是变量a的值
   console.log(b);   // 我是变量b的值

上面代码是声明了变量a我是a的变量的a然后声明变量b,并把变量a赋值给变量b,输出,得出变量ab输出的值是一样的。 单独更改了变量b的值,再输出的时候发现变量ab输出的值不一样了,可以证明他们两个的值是单独存在的,互相没有联系,就算var b = a,也只是新增了一个变量b和值。

复杂数据类型(引用类型)

   // 引用类型
var obj1 = {
  a: 'a',
  b: 'b'
}
var obj2 = obj1;

console.log(obj1); // { a: 'a', b: 'b' }
console.log(obj2); // { a: 'a', b: 'b' }

obj2.b = 'bb';

console.log(obj1); // { a: 'a', b: 'bb' }
console.log(obj2); // { a: 'a', b: 'bb' }

在上面的代码中能发现,在引用类型直接的赋值,声明变量obj1为一个对象,然后让讲变量obj1赋值给obj2,这时候输出的变量obj1和变量obj2的值是一样的
当更改了obj2.b的值以后,输出结果发现obj1.b的值也跟着发生了变化
这就是要注意的,引用类型的赋值只是给了一个对内存中对象引用的一个指针,所以变量obj1和变量obj2是引用了同一个内存中的对象,所以当一个更改以后,另一个也会跟着改变。

克隆原理图

image.png

深克隆

深克隆——Object.assign()

*Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。————————《MDN web docs》

Object.assign(target, ...sources) 这是MDN文档中对Object.assign()这个方法的说明,其实就是这个方法可以穿入两个参数,第一个参数是目标函数,第二个参数是源对象,然后会把源对象的可枚举到的属性复制到目标函数中,然后返回目标对象,也就是更改了目标对象。

// 声明目标对象和源对象
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
// 将源对象上可枚举的属性复制到目标对象上,有相同键值的覆盖
const returnedTarget = Object.assign(target, source);

console.log(source); // { b: 4, c: 5 }

console.log(target); // { a: 1, b: 4, c: 5 }

console.log(returnedTarget); // { a: 1, b: 4, c: 5 }

实现深克隆

  1. 判断数据类型,分别处理
  2. 递归

/**
 * 常量
 * @type {string}
 */
const TYPE_OBJECT = '[object Object]';
const TYPE_ARRAY = '[object Array]';
/**
 * 判断对象的类型
 * @param obj 来源对象
 * @returns {string} 对象类型
 */
function typeToString(obj) {
  return Object.prototype.toString.call(obj)
}

/**
 * 深克隆对象
 * @param oldObj 源对象
 * @returns {Object} 返回克隆后的对象
 */
function deepClone(oldObj) {
  let newObj;
  if ( oldObj === null ) {
    return null
  }
  if ( typeof oldObj !== 'object') {
    return oldObj
  }
  switch (typeToString(oldObj)) {
    case TYPE_OBJECT:
      newObj = {}
      break;
    case TYPE_ARRAY:
      newObj = [];
      break;
  }
  for (let i in oldObj) {
    newObj[i] = deepClone(oldObj[i]);
  }
  return newObj
}

实践————Lodash的_.cloneDeep

Lodash是什么?Lodash是一个一致性、模块化、高性能的JavaScript实用工具库。

import _ from 'lodash';

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

可以说lodash在深克隆方法的实现上,不仅有数据类型的判断,还有浮点数的判断,多少位的浮点数的判断,以及边界考虑。