【JS】赋值、浅拷贝与深拷贝


JavaScript中存在两大数据类型:

  • 基本类型
    • Number类型
    • String类型
    • Boolean类型
    • Null类型
    • Undefined类型
    • Biglnt类型
    • 字符串类型
    • 符号类型
  • 引用类型
    • Object 类型
    • Array 类型
    • Date 类型
    • RegExp 类型
    • Function 类型

基本类型:保存在在栈内存中,它们的值直接存储在变量访问的位置,在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,它们只是拥有相同的 value 而已,a 不全等 b。
引用类型:保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中,在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,它们中任何一个作出的改变都会影响另一个,a 全等 b,因为它们的指针指向同一个堆内存。

原数据

let a = {
    name: '张三',
    age: 19,
    list: [1, 2, 3]
},
arr = [4,5,6];

赋值

  • 对象数组赋值给一个新的变量时,其实是赋的内存地址,而不是对象中的数据。所以修改一个将影响另外一个。
let b= a;
a.age = 20;
a.list = arr;
a.list[0] = '3';
console.log(a);  // {name: "张三", age: 20, list:["3", 5, 6]}
console.log(b);  // {name: "张三", age: 20, list:["3", 5, 6]}
console.log(arr);      // ["3", 5, 6]

浅拷贝

  • 浅拷贝是创建新的数据,重新在堆中创建内存,拷贝的是基本类型则互不影响,但是拷贝的引用类型共享同一个内存地址,会互相影响
const deepClone=(obj)=> {
    const newObj = {};
    for(let prop in obj) {
        if(obj.hasOwnProperty(prop)){
            newObj[prop] = obj[prop];
        }
    }
    return newObj;
}
let b= deepClone(a);
console.log(b);  // {name: "张三", age: 19, list: [1, 2, 3]}
b.age = 20;
b.list[0] = '3';
console.log(a);  // {name: "张三", age: 19, list:["3", 2, 3]}
console.log(b);  // {name: "张三", age: 20, list:["3", 2, 3]}

深拷贝

  • 深拷贝是从堆内存中从新创建一个区域来存放新对象,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,互不影响。

常见的深拷贝方式

  • _.cloneDeep()
  • JSON.stringify()
  • 手写循环递归
  • jQuery.extend()

_.cloneDeep()

const _ = require('lodash');
let b= _.cloneDeep(a);
console.log(a.list===b.list);  // false

JSON.stringify()

let a = {
    c: 'c',
    c1: undefined,
    c2: function() {},
    c3:  Symbol('c')
}
let b= JSON.parse(JSON.stringify(a));
// 存在弊端 会忽略undefined、symbol和函数
console.log(b); // {c: "c"}

手写循环递归

const deepClone=(obj, hash = new WeakMap()) =>{
  // 如果为null或者undefined则不进行拷贝操作
  if (obj === null) return obj; 
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

//调用函数
deepClone(a)

jQuery.extend()

const $ = require('jquery');
let b= $.extend(true, {}, a);
console.log(a.list===b.list);  // false
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值