JavaScript 变量类型 和 深度克隆

对以前写过的博客进行补充和回顾 https://www.jianshu.com/p/9c818497f25f

一、基本数据类型

Number String Boolean Undefined Null Symbol(ES6)

基本数据类型存放于栈内存。包括变量标识符和变量的值

let a = 1;
let b = 2;
image

基本类型赋值后两个变量互不影响

let a = 10;
let b = a;
image

二、引用数据类型

引用类型的存储需要内存的栈区和堆区共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址,而堆内存中存储这个对象

let person1 = {name:'张三'};
let person2 = {name:'张三'};
let person3 = person1;
image

引用类型的赋值是地址的复制,所以两个变量指向的还是同一个对象,对任何一个的操作都会相互的影响

person3.name = '李四'
console.log(person1.name) // 李四

三、使用深度克隆的几种方式

1. Object.assign的方式

function cloneDeep(obj) {
  return Object.assign({}, obj);
}

MDN:Object.assign讲解

弊端:

  • 假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。这时候对于嵌套的对象深度拷贝是无效的。例如下面的——

    let oldObj = {
      name: '张三',
      friend: {
        name: '李四'
      }
    };
    

2. JSON.parse()和JSON.stringify()的方式

function cloneDeep(obj) {
  return JSON.parse(JSON.stringify(obj));
}

这种方式实现通过 JSON.stringify()将对象或数组进行JSON字符串化,这时候他就是一个基本数据类型,然后在通过JSON.parse进行解析。

MDN:JSON.stringify()讲解

MDN:JSON.parse()讲解

弊端:

  • 如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
  • 如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;
  • 如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
  • 如果obj里有NaN、Infinity和 - Infinity,则序列化的结果会变成null

3. 相对全面的一个方式

function cloneDeep(obj) {

  if (typeof obj !== 'object') {
    return obj;
  }

  if (!obj) {  // obj 是 null的情况
    return obj;
  }

  if (obj instanceof Date) {
    return new Date(obj);
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  if (obj instanceof Function) {
    return obj;
  }

 // 定义一个新的空数组或者对象
  let newObj = Array.isArray(obj) ? [] : {}
  if (obj && typeof obj === "object") {
    for (let key in obj) {
      // 执行 hasOwnProperty() 来确定某属性是否是对象本身的属性
      if (obj.hasOwnProperty(key)) {
        newObj[key] = (obj && typeof obj[key] === 'object') ? cloneDeep(obj[key]) : obj[key];
      }
    }
  }
  return newObj;
    
}

弊端:

  • 较为复杂

4. 直接使用lodash中的方法

项目中使用最好使用他人已经分装好的库来使用,比我们考虑的更为周全和简洁。这里推荐lodash,lodash 是一个 JavaScript 的实用工具库,众多常用的方法他都给我们封装好了

点击查看lodash文档

下面一个官网栗子

直接引用库,然后调用其方法即可

const _ = require('lodash')

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

你可能感兴趣的:(JavaScript 变量类型 和 深度克隆)