拷贝

赋值(Copy)

赋值是将某一数值或者对象赋给某个变量的过程,分为2部分

  • 基本数据类型:赋值,复制之后两个变量互不影响。
  • 引用数据类型:赋址,两个变量之间具有相同的引用,指向同一个对象。相互之间有影响。

对于基本类型进行赋值操作,两个变量互不影响。

  1. var a='name';
  2. var b=a;
  3. a = 'change'
  4. // a change ; b name;

对于引用类型进行赋址操作,两个变量指向同一个对象,改变a对象之后,会影响b对象。

通常在开发中并不希望改变变量a之后会影响到变量b。所以需要进行深拷贝和浅拷贝。

浅拷贝(Shallow Copy)

定义

浅拷贝,创建一个新的对象,这个对象有着原始对象属性值的的一份精确拷贝。如果属性值是基本类型,拷贝的就是基本类型结果。如果属性是引用类型,拷贝的就是内存地址。
简单的说:浅拷贝只解决了第一层的问题。拷贝第一层的基本类型值,以及第一层的引用类型地址。

场景

  • Object.assign()

方法用于将所有可枚举属性值从一个或多个源对象复制到目标对象,并返回目标对象

  • 展开语法Spread
  • Array.prototype.slice()

方法返回一个新的数组对象,这一个对象室友begin和and(不包括end),决定原来数组的浅拷贝,原始数组不会改变。

深拷贝

定义

深拷贝会拷贝所有属性,并拷贝属性指向的动态分配额内存,当对象和他所引用的对象一起拷贝是即发生深拷贝。深拷贝相对于浅拷贝速度慢,开销大。拷贝前后两个对象互不影响。

使用场景
JSON.parse(JSON.stringfy(obj))
使用此方法的几个问题。

  1. 会忽略undefined,symbol,函数
  2. 不能解决循环引用的对象,会报错。
  3. 不能正确处理new Date()
  4. 不能处理正则。
  1. let obj = {
  2. a: 1,
  3. b: {
  4. c: 2,
  5. d: 3
  6. }
  7. }
  8. obj.a = obj.b;
  9. obj.b.c = obj.a;
  10. let b = JSON.parse(JSON.stringify(obj));
  11. // Uncaught TypeError: Converting circular structure to JSON
  1. new Date();
  2. // Mon Dec 24 2018 10:59:14 GMT+0800 (China Standard Time)
  3. JSON.stringify(new Date());
  4. // ""2018-12-24T02:59:25.776Z""
  5. JSON.parse(JSON.stringify(new Date()));
  6. // "2018-12-24T02:59:41.523Z"
  1. let obj = {
  2. name: "muyiy",
  3. a: /'123'/
  4. }
  5. console.log(obj);
  6. // {name: "muyiy", a: /'123'/}
  7. let b = JSON.parse(JSON.stringify(obj));
  8. console.log(b);
  9. // {name: "muyiy", a: {}}

常用的有jQuery.exend() lodash.cloneDeep()

lodash实现

位掩码

  1. // 木易杨
  2. // 主线代码
  3. const CLONE_DEEP_FLAG = 1 // 1 即 0001,深拷贝标志位
  4. const CLONE_FLAT_FLAG = 2 // 2 即 0010,拷贝原型链标志位,
  5. const CLONE_SYMBOLS_FLAG = 4 // 4 即 0100,拷贝 Symbols 标志位

位掩码用于处理同时存在多个布尔选项的情况,其中掩码中的每个选项的值都等于 2 的幂。相比直接使用变量来说,优点是可以节省内存(1/32)

  1. // 木易杨
  2. // 主线代码
  3. // cloneDeep.js 添加标志位,1 | 4 即 0001 | 0100 即 0101 即 5
  4. CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG
  5. // baseClone.js 取出标志位
  6. let result // 初始化返回结果,后续代码需要,和位掩码无关
  7. const isDeep = bitmask & CLONE_DEEP_FLAG // 5 & 1 即 1 即 true
  8. const isFlat = bitmask & CLONE_FLAT_FLAG // 5 & 2 即 0 即 false
  9. const isFull = bitmask & CLONE_SYMBOLS_FLAG // 5 & 4 即 4 即 true

常用的基本操作如下

  • a|b:添加标志位a和b
  • mask & a取出标志位a
  • mask & ~a清楚标志位a
  • mask ^ a:取出与a的不同部分
  1. // 木易杨
  2. var FLAG_A = 1; // 0001
  3. var FLAG_B = 4; // 0100
  4. // 添加标志位 a 和 b => a | b
  5. var mask = FLAG_A | FLAG_B => 0101 => 5
  6. // 取出标志位 a => mask & a
  7. mask & FLAG_A => 0001 => 1
  8. mask & FLAG_B => 0100 => 4
  9. // 清除标记位 a => mask & ~a
  10. mask & ~FLAG_A => 0100 => 4
  11. // 取出与 a 的不同部分 => mask ^ a
  12. mask ^ FLAG_A => 0100 => 4
  13. mask ^ FLAG_B => 0001 => 1
  14. FLAG_A ^ FLAG_B => 0101 => 5