js 什么是深拷贝问题?

1、什么是值类型?redux

2、什么是引用类型?数组

3、使用ES Next新特性带来的 Object.assign 方法 和 扩展运算符;工具

4、Object.assign 方法 和 扩展运算符的 “深刻浅出” 问题 —— 浅拷贝;性能

5、解决深拷贝问题常见的三种方法。spa

 


 

在 JavaScript 中,数据类型包括:3d

一、基本数据(值)类型,如 undefined、null、number、boolean、string等code

二、引用类型:如Object、Array、Function等。对象

 

1、什么是值类型?blog

var a = 1; var b = a; b = b + 1 console.log(a, b) // 1, 2

值类型赋值时,会在栈内存空间中分配全新的地址,并获得相应的值。代码中 b 是从 a 建立来的,当 b 变化时,a 不会受到影响。这是符合常识的。递归

 

2、什么是引用类型?

var data = { id: 0, book: 'learn redux', avaliable: false }
var newData = data

newData.id
= 1; console.log(data.id, newData.id) // 1 1

再来看看引用类型(以Object对象为例),对象实际是存在于堆内存空间中。当咱们要访问一个对象的时候,其实是从栈内存中获取引用地址,而后根据这个引用地址再从堆内存中获取所须要的值。

而引用类型赋值时,其实是获取其引用地址,而不是直接获取值。因此,值发生改变时,源对象也会随着改变。

 

3、使用ES Next新特性带来的 Object.assign 方法 和 扩展运算符

使用 Object.assign({}, ...) 来解决 "单层"对象 引用问题

let data = { id: 0, book: 'learn redux', avaliable: false }
let newData
= Object.assign({}, data)
newData.id
= 1; console.log(data.id, newData.id) // 0 1

 或者使用对象的扩展运算符

var data = { id: 0, book: 'learn redux', avaliable: false } var newData = {title: 'fuck', ...data}; newData.id = 1; console.log(data.id, newData.id) // 0 1

(PS:JavaScript的数组也是引用类型,同理能够使用 Array.concat 方法 和 数组的扩展运算符来解决引用问题,这里就省略了)

 

4、Object.assign 方法 和 扩展运算符的 “深刻浅出” 问题 —— 浅拷贝

须要注意的是,使用 Object.assign 及 扩展运算符都属于浅操做。若是往对象的外面再套一层的话,那问题就会浮现出来了。

var data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } var newData = Object.assign({}, data) newData.item.id = 1; console.log(data.item.id, newData.item.id) // 1 1

上述的结果代表,原始数据仍是被更改了。

 

 

 

5、解决深拷贝问题常见的三种方法

一、jQuery的深拷贝工具: $.extend(true, ...)

let data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } }
// 首参必须设置为 true 才算是深拷贝 let newData
= $.extend(true, {}, data); newData.item.id = 1 console.log(data.item.id, newData.item.id) // 0 1

为何$.extend默认不使用深拷贝,还须要手动传参true才开启呢?

这是由于深拷贝在实战中是比较消耗性能的,如无必要请使用浅拷贝便可。稍后咱们会实现一个本身的深拷贝工具。你能够从中了解详情。

 

 

二、巧用序列化:JSON.parse(JSON.stringify(...))

let data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } let newData = JSON.parse(JSON.stringify(data)) newData.item.id = 1 console.log(data.item.id, newData.item.id) // 0 1

原理很简单,就是先将对象转换为字符串,再从新序列化为对象,这样理所固然不会有引用问题。值得一提的是,这些操做对数组也是有效的。

 

 

三、递归拷贝(深拷贝)

在咱们封装一个本身的深拷贝工具以前,咱们须要先跳过一些可能的拷贝错误认知 —— “不要单纯的认为,只要是拷贝嵌套对象就会产生深拷贝问题”。

(1)就算是拷贝嵌套对象,若是操做的只是基本数据类型,不会有影响的。

let data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } let newData = Object.assign({}, data); newData.title = 'fuck' console.log(data.title, newData.title) // 123 fuck

(2)就算是嵌套对象,若是只拷贝其中一层对象,是不会产生问题的。

let data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } let newData = Object.assign({}, data.item); newData.id = 1; console.log(data.item.id, newData.id) // 0 1

 

有了以上两个认知,实际上咱们能够实现手动深拷贝了。

let data = { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } // 建立一个空对象
let newData = {} // 基本数据类型,能够直接拿
newData.title = data.title // data.item对象,其实能够使用 Object.assign 来拿 // newData.item = Object.assign({}, data.item)

// 但为了体现手动深拷贝细节,仍是一步一步来吧。 // 经过对data.item拆解,item对象被转换为一个个的基本数据类型直接赋值给newData.item的每一项 // 若是 item 还有对象的话,那就只能依样画葫芦继续拆解。直到变成基本数据类型为止。
newData.item = {} newData.item.id = data.item.id newData.item.book = data.item.book newData.item.avaliable = data.item.avaliable newData.item.id = 1 console.log(data.item.id, newData.item.id) // 0 1

经过对data.item拆解,item对象就转换为一个个的基本数据类型了,因此能够直接赋值给newData.item的每一项了。

若是 item 还有对象的话,那就只能依样画葫芦继续拆解。直到变成基本数据类型为止。

 

知道了如何手动深拷贝,如今咱们把他转换为自动化深拷贝,常见的的实现方式是递归拷贝了:

// 递归深拷贝
var
deepExtend = function(out) { out = out || {}; for (var i = 1; i < arguments.length; i++) { var obj = arguments[i]; if (!obj) continue; for (var key in obj) { if (obj.hasOwnProperty(key)) { if (typeof obj[key] === 'object') out[key] = deepExtend(out[key], obj[key]); else out[key] = obj[key]; } } } return out; };
// demo let data
= { title: '123', item: { id: 0, book: 'learn redux', avaliable: false } } var newData = deepExtend({}, data); newData.item.id = 1 console.log(data.item.id, newData.item.id) // 0 1

 

相关文章
相关标签/搜索