深度克隆(deepclone)

深度克隆(deepclone)

深度克隆方法,返回一个新的克隆对象
这里得说明深拷贝与钱拷贝的区别,浅拷贝是复制一个对象的引用,深拷贝是chone一个新的对象,与原对象有着不同的内存地址

一 . 补充说明,如何判断 原始值 和 *引用值

一. 基本知识

1.数据类型

1.1 原始值类型

     String  Number  function  Boolean  undefined  Symbol(es6引入)

1.2 引用值类型

   Object  Array  Null     
  ```
**1.3 判断基本类型**
```js
使用 typeOf 进行判断  

//  原始值类型
console.log(typeof 'sfsf') // "string"
console.log(typeof 22) // "number"
console.log(typeof function(){}) // "function"
console.log(typeof true) // "boolean"
console.log(typeof undefined) // "undefined"
console.log(typeof Symbol('2')) // "symbol"

//  引用值类型
console.log(typeof {})  //"object"
console.log(typeof [])  // "object"
console.log(typeof null) // "object"
2. 判断对像和数组

2.1 constructor

[].constructor == Array   
[].constructor == Array / Object     

弊端此方法容易被改写

let arr = [];                         
arr.constructor = Object                           
console.log(arr.constructor == Array)   // false                         
console.log(arr.constructor == Object)  // true      

2.2 instanceof
运算符可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。

console.log([] instanceof Array) // true                    
console.log([] instanceof Object) // true                     
console.log({} instanceof Array) // false                   
console.log({} instanceof Object) // true  

判断一个Object是不是数组(这里不是口误,在JavaScript当中,数组实际上也是一种对象),如果这个Object的原型链上能够找到Array构造函数的话, 那么这个Object就也是一个数组,如果这个Object的原型链上只能找到Object构造函数的话,那么它就不是一个数组。
2.3 Object.prototype.toString.call() 建议

Object.prototype.toString.call([])  //"[object Array]"
Object.prototype.toString.call({})  //"[object Object]"
Object.prototype.toString.call(null) //"[object Null]"

注意,这里的call改变this的指向是必不可少的,如果缺少

Object.prototype.toString([])  //"[object Object]"                  
Object.prototype.toString({})  //"[object Object]"                  
Object.prototype.toString(null) //"[object Object]"            

二.实现:

方法一

通过递归遍历一个对象,返回一个新的对象

/**
 * 深拷贝
 * @param {*} target 要深拷贝的值
 */
function deepclone(target) {
  if (typeof target !== "object") return target;

  let obj;
  if (!Array.isArray) {
    Array.isArray = function(arg) {
      return Object.prototype.toString.call(arg) === "[object Array]";
    };
  }
  if (Array.isArray(target)) {
    obj = [];
  } else {
    obj = {};
  }
  for (let prop in target) {
    // obj.hasOwnProperty 判断某个对象是否含有指定的属性
    // 该方法会忽略掉从原型链上继承的属性
    if (target.hasOwnProperty(prop)) {
      if (typeof target === "object") {
        obj[prop] = deepclone(target[prop]);
      } else {
        obj[prop] = target[prop];
      }
    }
  }
  return obj;
}

console.log(deepclone({ a: 1, b: { c: 2 } })); // 打印 { a: 1, b: { c: 2 } }
console.log([1, 23, { a: 2 }]); // 打印 [1, 23, { a: 2 }]
console.log(deepclone(5)); // 打印 5

方法二

通过hack方式实现

function deepclone(target) {
  return JSON.parse(JSON.stringify(target));
}

console.log(deepclone({ a: 1, b: { c: 2 } })); // 打印 { a: 1, b: { c: 2 } }
console.log([1, 23, { a: 2 }]); // 打印 [1, 23, { a: 2 }]
console.log(deepclone(5)); // 打印 5

方法三

通过Object.getPrototypeOf() 获取目标对象的原型,通过Object.assign()生成一个新的对象

function deepclone(target) {
  if (typeof target !== "object") return target;
  return Object.assign(
    {},
    Object.create(Object.getPrototypeOf(target)),
    target
  );
}

console.log(deepclone({ a: 1, b: { c: 2 } })); // 打印 { a: 1, b: { c: 2 } }
console.log([1, 23, { a: 2 }]); // 打印 [1, 23, { a: 2 }]
console.log(deepclone(5)); // 打印 5

方法四

通过Object.getPrototypeOf() 获取目标对象的原型,通过扩展运算符以及proto来实现深度克隆(仅适用于浏览器端)

function deepclone(target) {
  if (typeof target !== "object") return target;
  return {
    __photo__: Object.getPrototypeOf(target),
    ...target
  };
}

console.log(deepclone({ a: 1, b: { c: 2 } }));
console.log([1, 23, { a: 2 }]);
console.log(deepclone(5));

你可能感兴趣的:(JS)