We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Learn more about funding links in repositories.
Report abuse
There was an error while loading. Please reload this page.
第71天 说说你对深浅拷贝的理解?并实现一个对数组和对象深拷贝的方法
这道题跟第44天的题类似。多了说明深浅拷贝的理解,同时方法多了对数组的支持。 第44天的题:#167
var obj1={ value: 'a' } var obj2 = obj1; obj2.value='b'; console.log(obj1);//{ value: 'b' }
因为对象是引用类型,所以赋值时的操作仅是赋予相同的地址,当对其中一个对象进行操作时,就会影响其他的对象。解决这个问题就需要拷贝了。
使用原生的Object.assign() 方法就可以实现浅拷贝
Object.assign()
var obj1={ value: 'a' } var obj2 = Object.assign({},obj1); obj2.value='b'; console.log(obj1);//{ value: 'a' }
但是如果拷贝的源对象当中包含对象时,OBject.assign()方法只会拷贝对象的引用地址
OBject.assign()
var obj1={ value: 'a', obj3:{ value2: 'c' } } var obj2 = Object.assign({},obj1); obj2.obj3.value2='b'; console.log(obj1);//{ value: 'a', obj3:{ value2: 'b' } }
如果要拷贝的对象中包含对象,就需要深拷贝了,一般使用原生的方法JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj))
j1={ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.obj3.value2='b'; obj2.arr[0]= "a"; console.log(obj2);//{ value: 'a', obj3:{ value2: 'b' }, arr:['a',2,3] } console.log(obj1);//{ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } 没有发生改变
var obj={ name: 'znl', age: 18, friend:{ name: 'borys', age: 20 }, arr:[1,2,[3,4]] } function copy(obj){ var type=Object.prototype.toString.call(obj); if(!(type == '[object Array]' || type == '[object Object]')){ return 'Type Error!'; } return JSON.parse(JSON.stringify(obj)); } var obj2= copy(obj); console.log(obj.friend === obj2.friend)//false console.log(obj.arr === obj2.arr)//false
参考:
浅拷贝 vs 深拷贝
补充一个用到的数组浅拷贝的方法 Array.from()
Array.from()
function clone (obj) { let buf if (obj instanceof Array || (obj instanceof Object && typeof obj !== 'function')) { buf = obj instanceof Array ? [] : {} for (let key in obj) { if (obj.hasOwnProperty(key)) { buf[key] = clone(obj[key]) } } } else { return obj } return buf }
function deepClone (obj) { //判断克隆对象为数组还是对象 var newObj = obj.constructor === Array ? [] : {}; for (var item in obj) { //若数组元素或对象属性为'object'则递归调用自身深度克隆对象或数组 if (typeof obj[item] === 'object') { newObj[item] = deepClone(obj[item]); } //基本数据类型直接赋值 else { newObj[item] = obj[item]; } } return newObj; }
function deepClone(val) { function getType(_val) { return Object.prototype.toString.call(_val).replace(/[\[\s\]]|(object)/g, '') } const valType = getType(val); if (valType !== 'Object' && valType !== 'Array') return val let output = {} if (valType === 'Array') { output = [] val.forEach(v => { const curValType = getType(v) if (curValType === 'Array' || curValType === 'Object') { output.push(deepClone(v)) } else { output.push(v) } }) } else if (valType === 'Object') { Object.keys(val).forEach(v => { const curValType = getType(v) if (curValType === 'Array' || curValType === 'Object') { output[v]= (deepClone(val[v])) } else { output[v]= (val[v]) } }) } return output } const obj = { a: 1, b: [ { b1: 'b1', b2: { b2_1: 'b2_1' } } ] } const clone = deepClone(obj) obj.b = { b: 'b' } console.log(clone) console.log(obj)
https://gist.github.com/48d32a1b619e59d9f0f2a23aaa68aa5c
// WeakMap + new obj.constructor() // 考虑了 Data,RegExp,循环引用,没处理Symbol,Set,Map等 function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== "object") return obj; // 值类型 if (obj instanceof RegExp) return new RegExp(obj); // RegExp类型 if (obj instanceof Date) return new Date(obj); // Dete类型 //! 以下是针对Object类型的处理逻辑 if (hash.has(obj)) return hash.get(obj); // 防止循环引用 const temp = new obj.constructor(); // 基于constructor创建新类 hash.set(obj, temp); // 在WeakMap中缓存 for (const key in obj) { if (obj.hasOwnProperty(key)) // 递归处理自身属性 temp[key] = deepClone(obj[key], hash); } return temp; }
为什么要进行拷贝 var obj1={ value: 'a' } var obj2 = obj1; obj2.value='b'; console.log(obj1);//{ value: 'b' } 因为对象是引用类型,所以赋值时的操作仅是赋予相同的地址,当对其中一个对象进行操作时,就会影响其他的对象。解决这个问题就需要拷贝了。 浅拷贝: 使用原生的Object.assign() 方法就可以实现浅拷贝 var obj1={ value: 'a' } var obj2 = Object.assign({},obj1); obj2.value='b'; console.log(obj1);//{ value: 'a' } 但是如果拷贝的源对象当中包含对象时,OBject.assign()方法只会拷贝对象的引用地址 var obj1={ value: 'a', obj3:{ value2: 'c' } } var obj2 = Object.assign({},obj1); obj2.obj3.value2='b'; console.log(obj1);//{ value: 'a', obj3:{ value2: 'b' } } 深拷贝 如果要拷贝的对象中包含对象,就需要深拷贝了,一般使用原生的方法JSON.parse(JSON.stringify(obj)) j1={ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.obj3.value2='b'; obj2.arr[0]= "a"; console.log(obj2);//{ value: 'a', obj3:{ value2: 'b' }, arr:['a',2,3] } console.log(obj1);//{ value: 'a', obj3:{ value2: 'c' }, arr:[1,2,3] } 没有发生改变 实现一个对数组和对象的深拷贝的方法 var obj={ name: 'znl', age: 18, friend:{ name: 'borys', age: 20 }, arr:[1,2,[3,4]] } function copy(obj){ var type=Object.prototype.toString.call(obj); if(!(type == '[object Array]' || type == '[object Object]')){ return 'Type Error!'; } return JSON.parse(JSON.stringify(obj)); } var obj2= copy(obj); console.log(obj.friend === obj2.friend)//false console.log(obj.arr === obj2.arr)//false 参考: MDN Object.assign 深拷贝
由于对象是引用类型,对于赋值的操作只是赋予相同的地址,当对其中的一个对象进行操作时,另外一个对象也会改变。解决这个问题就需要拷贝了。 浅拷贝:Object.assign可以实现浅拷贝,只会拷贝对象的引用地址。 深拷贝:对象和数组都可以 var result = {} var res = (function(_) { var types = 'String Null Undefind Date RegExp Object Array Boolean'.split(' ') function type() { return Object.prototype.toString.call(this).slice(8, -1) } for(var i=0;i<types.length;i++){ _['is'+types[i]] = (function(){ return function(ele) { return type.call(ele) } })(types[i]) } return _ })(result) function deepClone(target){ let result if (res.isArray(target) === 'Array') { result = [] for(let o in target) { result.push(deepClone(target[o])) } }else if(res.isObject(target) === 'Object') { result = {} for(let o in target) { result[o] = deepClone(target[o]) } } else { // 基本数据类型 result = target } return result } let originData = deepClone(origin) origin.b[1] = 6 console.log(origin) console.log(originData)
Activity
haizhilin2013 commentedon Jun 25, 2019
这道题跟第44天的题类似。多了说明深浅拷贝的理解,同时方法多了对数组的支持。
第44天的题:#167
AnsonZnl commentedon Jun 26, 2019
为什么要进行拷贝
因为对象是引用类型,所以赋值时的操作仅是赋予相同的地址,当对其中一个对象进行操作时,就会影响其他的对象。解决这个问题就需要拷贝了。
浅拷贝:
使用原生的
Object.assign()
方法就可以实现浅拷贝但是如果拷贝的源对象当中包含对象时,
OBject.assign()
方法只会拷贝对象的引用地址深拷贝
如果要拷贝的对象中包含对象,就需要深拷贝了,一般使用原生的方法
JSON.parse(JSON.stringify(obj))
实现一个对数组和对象的深拷贝的方法
参考:
MY729 commentedon Jul 2, 2019
浅拷贝 vs 深拷贝
补充一个用到的数组浅拷贝的方法
Array.from()
Kntt commentedon Jul 5, 2019
chenyouf1996 commentedon Jul 29, 2019
rni-l commentedon Jan 20, 2020
Cyrusky commentedon Feb 9, 2020
https://gist.github.com/48d32a1b619e59d9f0f2a23aaa68aa5c
summarychm commentedon May 11, 2020
smile-2008 commentedon Jan 15, 2021
xiaoqiangz commentedon Jun 17, 2022
由于对象是引用类型,对于赋值的操作只是赋予相同的地址,当对其中的一个对象进行操作时,另外一个对象也会改变。解决这个问题就需要拷贝了。
浅拷贝:Object.assign可以实现浅拷贝,只会拷贝对象的引用地址。
深拷贝:对象和数组都可以
var result = {}
var res = (function(_) {
var types = 'String Null Undefind Date RegExp Object Array Boolean'.split(' ')
function type() {
return Object.prototype.toString.call(this).slice(8, -1)
}
for(var i=0;i<types.length;i++){
_['is'+types[i]] = (function(){
return function(ele) {
return type.call(ele)
}
})(types[i])
}
return _
})(result)
function deepClone(target){
let result
if (res.isArray(target) === 'Array') {
result = []
for(let o in target) {
result.push(deepClone(target[o]))
}
}else if(res.isObject(target) === 'Object') {
result = {}
for(let o in target) {
result[o] = deepClone(target[o])
}
} else { // 基本数据类型
result = target
}
return result
}
let originData = deepClone(origin)
origin.b[1] = 6
console.log(origin)
console.log(originData)