来源
1 .js中的对象是可变的,因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象会影响到原始对象
2 .为了解决这个问题,一般就是使用浅拷贝或者深拷贝来避免被修改,但是这样会造成cpu和内存的浪费
immutable Data
1 .一旦创建,就不能更改的数据,对immutable对象的任何修改或删除添加都会返回一个新的immutable对象
2 .实现原理就是持久化数据结构,在使用旧数据创建新数据的时候,会保证旧数据同时可用且不变,同时为了避免深度复制复制所有节点的带来的性能损耗,immutable使用了结构共享,即如果对象树种的一个节点发生变化,只修改这个节点和受他影响的父节点,其他节点则共享。
3 .优点
1 .immutable降低了Mutable带来的复杂度
2 .节省内存
3 .时间旅行,复制粘贴这些操作做起来非常简单
4 .并发安全:传统的并发需要加锁,但是这个数据是天生不可变的,所以并发所就不需要了
处理复杂对象
浅拷贝
深拷贝
1 .JSON.parse:利用jaon.pase将对象转换为其JSON字符串形式,然后将其解析回对象
1 .缺点:不能处理循环对象,子父节点互相引用的情况,无法处理对象中有function,正则等情况
2 .const deepClone(obj)=>JSON.parse(JSON.stringify(obj))
3 .详细操作[http://blog.sina.com.cn/s/blog_6ad6243801013egv.html](http://blog.sina.com.cn/s/blog_6ad6243801013egv.html)
2 .messageChannel
1 .messageChannel接口是信道通信api的一个接口,允许我们创建一个新的信道并通过信道的两个MessageProt属性传递数据
2 .类似的还有Histor API,Notification API.都是用了结构化克隆算法实现传输值的
function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = function(e){
console.log(e)
resolve(e.data)
}
port1.postMessage(obj);
});
}
const obj={name:"123"}
structuralClone(obj).then((e)=>{
console.log('clone',e)
})
console.log(obj)
obj.name="456"
console.log(obj,'change-->')
3 .
immutable
1 .如果需要频繁的操作一个复杂对象,每次完全拷贝一次的效率太低了。大部分场景下都只是更新了对象的一两个字段,其他字段都不变,对于这些不变的字段的拷贝都是多于的。
2 .核心思路,创建持久化的数据结构,在操作对象的时候值clone变化的节点和其祖先节点,其他的不变,实现结构贡献。
3 .Immutable.js
4 .Immer.js
5 .
自己写的全部深度克隆代码
function type(obj){
var type=Object.prototype.toString.call(obj)
var map={
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Undefined]': 'undefined',
'[object Null]' : 'null',
'[object Object]' : 'object'
}
if(obj instanceof Element){
return 'element'
}
return map[type]
}
function deepClone(item){
if(!item)return item
var types=['number','string','boolean'],result
if(types.includes(type(item))){
result=item
}
if(result===undefined){
if(type(item)==='array'){
console.log('arr')
result=[]
item.forEach((child,index,array)=>{
result[index]=deepClone(child)
})
}else if(type(item)==='object'){
if(item.nodeType&& typeof item.cloneNode=='function'){
retult=item.cloneNode(true)
//真实的复制函数并没有走到这里
}else if(!item.prototype){
// 检查是否是可循环的
if(item instanceof Date){
result=new Date(item)
}else{
result={}
for(var i in item){
result[i]=deepClone(item[i])
}
}
}else{
console.log('发现了其他类型')
}
}else{
result=item
}
}else{
console.log('123',result)
}
return result
}
let arr=[1,2,3]
var arr2=deepClone(arr)
console.log(arr2,'arr2')
arr.push(1)
console.log(arr2,'arr2-after')