js-克隆

84 阅读3分钟

1.浅克隆:只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用。
2.深克隆:是在引用类型的类中也实现了clone,是clone的嵌套,复制后的对象与原对象之间完全不会影响。

各种克隆方式的比较点:

  • 是否能克隆所有类型的属性值

  • 深克隆还是浅克隆

  • 是否能克隆原型(继承)属性

    var d = { dd: 1 } var obj = { a: 1, b: "qwe", c: function name(params) {

    }, d:d }

    obj.proto.e= 222 obj.proto.f= {dd: 123}

    // 看看能不能把上面的都克隆到

浅克隆

1. Object.assign()

Object.assign() 方法将所有可枚举(Object.propertyIsEnumerable() 返回 true)和自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。

例子1
var obj = {name: 'jack', age: '18'}; 
var newObj = Object.assign({}, obj);


例子2
let obj1 = {
    name: 'zhang',
    age: 10,
    friends: ['1',2,23]
}
let obj2 = Object.assign({}, obj1) // 第一个参数利用一个空对象
obj1.friends.push('4')
console.log(obj2)
//{ name: 'zhang', age: 10, friends: [ '1', 2, 23, '4' ] }

不过,采用这种方法克隆,只能克隆原始对象自有属性,不能克隆它原型属性(所继承的值)。如果想要保持继承链,可以采用下面的代码Object.creat()。

利用Obejct.create()和Obejct.assign()实现克隆原型属性

function clone(origin) { 
  var originProto = Object.getPrototypeOf(origin); 
  return Object.assign(Object.create(originProto), origin); 
} 
var obj = {name: 'jack', age: '18'}; 
obj.__proto__.e= 222

var newObj = clone(obj);

2.扩展运算符号

对象的扩展符号...

  • 可以实现浅克隆

  • 可以克隆原型属性

    let a = {hello:'world'} let obj = {name:'zhang',age:12,plus:a} let obj2 = {...obj}

    obj.name = 'wang' obj.plus.hello = 'hello'

    console.log(obj); // { name: 'wang', age: 12, plus: { hello: 'hello' } } console.log(obj2); // { name: 'zhang', age: 12, plus: { hello: 'hello' } }

    数组也可以使用 var arr = [1,2,3,4,5]; // 写法一: var newObj = [...arr];

    // 写法二: var [...newObj] = arr;

3.数组 Array.from()和arr.concat()

可以用ES6提供新方法Array.from()复制数组,此方法复制为浅拷贝

let newArr = Array.from(goalArr)
// Array.from() 和 Array.map() 差不多

let newArr = [].concat(goalArr)

4.浅克隆函数

function cloneObj(obj) { 
  if (typeof obj !== 'object') { 
    return obj; 
  }else { 
    var newobj = obj.constructor === Array ? [] : {}; 
    for (var i in obj) { 
      newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]; 
    } 
    return newobj; 
  } 
}

深克隆

1.代码原理

/* 深度克隆,断开引用 */
const deepClone = function(obj) {
  // 先检测是不是数组和Object
  // let isArr = Object.prototype.toString.call(obj) === '[object Array]';
  let isArr = Array.isArray(obj);
  let isJson = Object.prototype.toString.call(obj) === '[object Object]';
  if (isArr) {
    // 克隆数组
    let newObj = [];
    for (let i = 0; i < obj.length; i++) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  } else if (isJson) {
    // 克隆Object
    let newObj = {};
    for (let i in obj) {
      newObj[i] = deepClone(obj[i]);
    }
    return newObj;
  }
  // 不是引用类型直接返回
  return obj;
};

2.第三方库lodash

import _ from 'lodash'
let goal = _.cloneDeep(obj)

3.JSON.parse(JSON.stringify(obj))

  • 会忽略 undefined

  • 会忽略 symbol

  • 会忽略function,不会报错,不能序列化函数

  • 不能解决循环引用的对象

  • 可以解析有引用的数据

  • 可以深克隆纯数据引入、自有属性

  • 不会克隆原型属性

    let obj = { name: 'zhangsan', friends: ['lisi', 'baoqiang', 'dada'] } let obj3 = obj let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj3, 'obj3') obj3.name = 'zhangsi' console.log(obj, 'obj') console.log(obj3, 'obj3') console.log(obj2, 'obj2')

    // 变量定义的引用类型也可以 let a = { hello: '123' } let obj = { name: 'zhangsan', friends: ['lisi', 'baoqiang', 'dada'], haha:a }

    let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj2); /** 输出 { name: 'zhangsan', friends: [ 'lisi', 'baoqiang', 'dada' ], haha: { hello: '123' } } */