JavaScript 常用的拷贝方式

一、知识前提

1、数据类型:

  • 基础类型:Number、String、Boolean、Null、Undefined。变量是直接按值存放在栈内存中的简单数据段,可以直接访问。
  • 引用类型:存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型(如对象Object,数组Array等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

2、赋值、浅拷贝与深拷贝的区别

方式是否与原数据指向同一对象第一层数据为基础类型原数据包含子对象
赋值改变、原数据改变改变、原数据改变
浅拷贝改变、原数据不改变改变、原数据改变
深拷贝改变、原数据不改变改变、原数据不改变

二、Object 的拷贝

2.1、Object.assign(obj) —— 浅拷贝

拷贝的是(可枚举)属性值
假如源值是一个对象的引用,它仅仅会复制其引用值。

let obj1 = { a: 0 , b: { c: 0 , d: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2));
// { a: 0, b: { c: 0, d: 0}} 

// 修改属性a的 —— 第一层数据为基础类型
obj1.a = 1; 
console.log(JSON.stringify(obj1));
// { a: 1, b: { c: 0,  d: 0}} 
console.log(JSON.stringify(obj2));
// { a: 0, b: { c: 0, d: 0}} 

obj2.a = 2; 
console.log(JSON.stringify(obj1));
// { a: 1, b: { c: 0, d: 0}} 
console.log(JSON.stringify(obj2));
// { a: 2, b: { c: 0, d: 0}}


// 修改属性b中c的值,则因是引用值,obj1,obj2都会修改
obj2.b.c = 3; 
console.log(JSON.stringify(obj1));
// { a: 1, b: { c: 3, d: 0}} 
console.log(JSON.stringify(obj2));
// { a: 2, b: { c: 3, d: 0}} 


let obj1 = { a: 0 , b: { c: 0, d: 0}}; 
let obj2 = Object.assign({}, obj1); 
obj2.a = 1;
obj2.b = { c: 1, d: 1 };  //obj2.b的指针指向了{ c: 1, d: 1 },而不是obj1.b的{ c: 0, d: 0},因此不会修改obj1.b的值
console.log(JSON.stringify(obj1));
console.log(JSON.stringify(obj2));
// {"a":0,"b":{"c":0,"d":0}}
// {"a":1,"b":{"c":1,"d":1}}

参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

2.2、{…obj} —— 浅拷贝

ES6的语法,用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
等同于Object.assign()

2.3、JSON.parse(JSON.stringify(obj)) —— 深拷贝

obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1)); 
obj1.a = 4; 
obj1.b.c = 4; 
console.log(JSON.stringify(obj3));
// { a: 0, b: { c: 0}}

不足之处:

  1. 对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)
  2. 无法拷贝原对象原型链上的属性和方法

参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

三、Array的拷贝

3.1、array.slice() —— 浅拷贝

let array_b = [0,1,2,3];
let array_r = [{a:1,b:1},{a:2,b:2}];

let c_array_b = array_b.slice();
let c_array_r = array_r.slice();

console.log(JSON.stringify(c_array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]

// 修改1
c_array_b[0] = 10;
console.log(JSON.stringify(array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_b));
// [10,1,2,3]

// 修改2
c_array_r[0].a = 10;
console.log(JSON.stringify(array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]

// 修改3
c_array_r[0] = {a:10,b:10}; // c_array_r[0]的指针指向了{a:10,b:10},而不是array_r[0]的{"a":1,"b":1},因此不会修改array_r[0]的值
console.log(JSON.stringify(array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]
// [{"a":10,"b":1},{"a":2,"b":2}] 存现这种结果是因为执行了修改2的语句
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":10},{"a":2,"b":2}]

3.2、array.concat() —— 浅拷贝

与array.slice() 基本相同

let array_b = [0,1,2,3];
let array_r = [{a:1,b:1},{a:2,b:2}];

let c_array_b = array_b.concat();
let c_array_r = array_r.concat();

console.log(JSON.stringify(c_array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]

// 修改1
c_array_b[0] = 10;
console.log(JSON.stringify(array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_b));
// [10,1,2,3]

// 修改2
c_array_r[0].a = 10;
console.log(JSON.stringify(array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]

// 修改3
c_array_r[0] = {a:10,b:10}; // c_array_r[0]的指针指向了{a:10,b:10},而不是array_r[0]的{"a":1,"b":1},因此不会修改array_r[0]的值
console.log(JSON.stringify(array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]
// [{"a":10,"b":1},{"a":2,"b":2}] 存现这种结果是因为执行了修改2的语句
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":10},{"a":2,"b":2}]

3.3、[…array] —— 浅拷贝

let array_b = [0,1,2,3];
let array_r = [{a:1,b:1},{a:2,b:2}];

let c_array_b = [...array_b];
let c_array_r = [...array_r];

console.log(JSON.stringify(c_array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]

// 修改1
c_array_b[0] = 10;
console.log(JSON.stringify(array_b));
// [0,1,2,3]
console.log(JSON.stringify(c_array_b));
// [10,1,2,3]

// 修改2
c_array_r[0].a = 10;
console.log(JSON.stringify(array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":1},{"a":2,"b":2}]

// 修改3
c_array_r[0] = {a:10,b:10}; // c_array_r[0]的指针指向了{a:10,b:10},而不是array_r[0]的{"a":1,"b":1},因此不会修改array_r[0]的值
console.log(JSON.stringify(array_r));
// [{"a":1,"b":1},{"a":2,"b":2}]
// [{"a":10,"b":1},{"a":2,"b":2}] 存现这种结果是因为执行了修改2的语句
console.log(JSON.stringify(c_array_r));
// [{"a":10,"b":10},{"a":2,"b":2}]

3.4、JSON.parse(JSON.stringify(array)) —— 深拷贝

同 2.3节

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值