-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
深拷贝和浅拷贝的区别是什么?如何实现一个深拷贝? #17
Comments
深拷贝=>拷贝所有的属性,并且地址也与原来的不同,这样的话,你改变当前的属性也不会影响原来的 深拷贝的实现: |
浅拷贝与深拷贝
浅拷贝
深拷贝
|
深拷贝就是完全的复制一个对象出来,而且不会影响到原来的对象;浅拷贝只是复制了原对象的引用地址,如果修改了浅拷贝的对象,原对象也会跟着改变...萌新理解就这么多 |
浅拷贝与深拷贝主要是针对保存在堆内存里的复杂数据类型所给出的名词。 |
深拷贝:拷贝对象的属性并重新创建一个对象,不会影响原始值。可以通过JSON.stringfty()和JSON.parse()来实现 |
浅拷贝:复制的是其引用的地址,当原始值改变时,浅拷贝的值也进行相应变化 |
浅拷贝:原始类型为值传递;对象类型仍为引用传递只复制了对象的引用地址,修改其中任一的值,另一个值会随之变化。 |
所谓深浅拷贝,都是进行复制,那么区别主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变。 深拷贝:而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝。 深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。 深拷贝| 栈内存 | | 堆内存 | |
深拷贝和浅拷贝的区别深拷贝和浅拷贝主要针对对象和数组来说的。 深拷贝实现1、JSON.strigify 和 JSON.parse function deepClone(obj) {
let _obj = JSON.strigify(obj);
let newObj = JSON.parse(_obj);
return newObj;
} 2、递归 function deepClone(obj) {
let newObj = Array.isArray(obj) ? [] : {};
let key;
if(typeof obj !== 'object') {
return obj;
} else {
for(key in obj) {
if(obj.hasOwnProperty(key)) {
if(obj[key] && typeof obj[key] === 'object') {
newObj[key] = deepClone(obj[key])
} else {
newObj[key] = obj[key]
}
}
}
}
return newObj;
} |
浅拷贝只拷贝了引用类型的地址,修改被拷贝对象或者拷贝对象的属性值,另外一方也会随之改变; |
知识准备:
改变其中一个对象的属性值,两个对象的属性值都变了,因为obj和obj1都指向同一个地址引用。 浅拷贝
深拷贝
slice返回一个数组的浅拷贝,并且生成一个新的数组,改变新数组不会影响原数组。
concat()可以用来合并数组,并生成一个新的数组。 function deepCopy(arr1,arr2){ 对象
封装一个deepCopy来实现对象的深拷贝
|
首先我们讨论一下深/浅拷贝出现的背景
综上:
实现方式
JSON.parse(JSON.stringify(originObject ))的弊端
|
描述(来源,对比)
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = {...a}
let c = JSON.parse(JSON.stringify(a))
a.age = 2
console.log(b.age) // 1
a.jobs.first = 'native'
console.log(b.jobs.first) // native
console.log(c.jobs.first) // FE 浅拷贝的实现方法
深度拷贝的实现
function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}
var obj = {a: 1, b: {
c: b
}}
// 可以处理 undefined 和互相引用对象
(async () => {
const clone = await structuralClone(obj)
})()
|
本文基本参考 木易杨的Git上的理解,拜读过2遍 深拷贝与浅拷贝我觉得深拷贝与浅拷贝的区分离不开赋值方式的理解 赋值的方式有两种一种是基本数据赋值,如果修改a,或者b的值,相互不影响。类似于:
一种是引用数据赋址,如果修改a或者b里面的值,两个会一起变。类似于
使用赋值的方式来区分深拷贝,浅拷贝浅拷贝浅拷贝创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值。如果属性是饮用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。 我们使用浅拷贝的情况:
深拷贝深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所饮用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢且花销较大。拷贝前后两个对象互不影响。 使用深拷贝的场景
|
1,浅拷贝和深拷贝何为拷贝:简易理解为重新复制一份数据。
var obj2 = {
name: '小明',
age: 18,
eat: [1,[2,3],[4,5,6]]
}
var obj3 = clone(obj2)
obj3.name = '小明1'
obj3.eat[1] = [1,1]
console.log('obj2',obj2) //obj2 { name: '小明', age: 18, eat: [ 1, [ 1, 1 ], [ 4, 5, 6 ] ] }
console.log('obj3',obj3) //obj3 { name: '小明1', age: 18, eat: [ 1, [ 1, 1 ], [ 4, 5, 6 ] ] }
function clone(src){
const cloneObj = src instanceof Array ? [] : {}
for(var prop in src){
if(src.hasOwnProperty(prop)){
cloneObj[prop] = src[prop]
}
}
return cloneObj
}
//拷贝对象
var obj4 = {
name: '小明',
age: 18,
eat: [1,[2,3],[4,5,6]]
}
var obj5 = deepClone(obj2)
obj5.name = '小明1'
obj5.eat[1] = [1,1]
console.log('obj4',obj4) //obj4 { name: '小明', age: 18, eat: [ 1, [ 2, 3 ], [ 4, 5, 6 ] ] }
console.log('obj5',obj5) //obj5 { name: '小明1', age: 18, eat: [ 1, [ 1, 1 ], [ 4, 5, 6 ] ] }
//拷贝数组
let arr = [1,2,3,4,[5,6]]
let arr1 = deepClone(arr)
arr1[4] = [1,1]
console.log('arr',arr) //arr [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log('arr1',arr1) //arr1 [ 1, 2, 3, 4, [ 1, 1 ] ]
function deepClone(src){
const cloneObj = src instanceof Array ? [] : {}
for(var prop in src){
if(src.hasOwnProperty(prop)){
if(typeof prop == Object || typeof prop == Array){
cloneObj[prop] = deepClone(prop) //关键的一步。如果拷贝时,数据为引用类型,则对属性再进行一次拷贝取值
}else{
cloneObj[prop] = src[prop]
}
}
}
return cloneObj
}
2,浅拷贝的实现方式
const h = {
age: 18,
eat: {
food: 'apple'
}
}
const i = Object.assign({},h)
i.eat.food = 'noodle'
console.log(h) //{ age: 18, eat: { food: 'noodle' } }
console.log(i) //{ age: 18, eat: { food: 'noodle' } }
const arr2 = [1,2,3,{name: '小明'},[2,2]]
const arr3 = arr2.concat()
arr3[3].name = '小虹'
arr3[4] = [1,1]
console.log(arr2) //[ 1, 2, 3, { name: '小虹' },[2,2] ]
console.log(arr3) //[ 1, 2, 3, { name: '小虹' },[1,1] ] 3,深拷贝的实现方式
var _ = require('lodash')
const arr6 = [1,2,3,{name: '小明'}]
const arr7 = _.cloneDeep(arr6)
arr7[3].name = 'lodash'
console.log(arr6)
console.log(arr7) |
浅拷贝 和 深拷贝浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,一般对象类型为引用类型
深拷贝所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中, 是在内存中另辟一个新的地址。
注意点
|
浅拷贝
深拷贝
实现深拷贝
// 1.实现简单的深拷贝
const hanzo = [1,2,3,4];
const genji = JSON.parse(JSON.stringify(hanzo));
console.log(hanzo === genji); // false
hanzo.push(5);
genji.splice(0,1);
console.log(hanzo); // [1,2,3,4,5]
console.log(genji); // [2,3,4]
// 缺陷:只能实现一些简单的深拷贝。但是下面这种情况就不适合了。
// 2.
const obj = {
name: 'hanzo',
age: 38,
sayHello: function() {
console.log('半藏')
}
};
console.log(obj); // {name: "hanzo", age: 38, sayHello: ƒ}
const obj6 = JSON.parse(JSON.stringify(obj));
console.log(obj6); // {name: "hanzo", age: 38}
// sayHello 这个funciton 并没有没拷贝下来
// 原因:undefined、function、symbol 会在转换过程中被忽略,
// 所以如果对象中含有一个函数时(很常见),就不能用这个方法进行深拷贝。 2. 递归
function deepCopy(source) {
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source) {
if(source[keys] && typeof source[keys] === 'object') { // 如果值是对象,就递归一下
targetObj[keys] = source.constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
} else {
targetObj[keys] = source[keys];
}
}
return targetObj
}
const hanzo = {
name: 'hanzo',
age: 38,
sayHello: function() {
console.log('我是半藏')
}
}
const genji = deepCopy(hanzo);
genji.name = 'genji';
genji.age = 35;
genji.sayHello = function() {
console.log('我是源氏')
};
console.log(hanzo); // {name: "hanzo", age: 38, sayHello: ƒ}
console.log(genji); // {name: "genji", age: 35, sayHello: ƒ}
console.log(hanzo === genji); // false
hanzo.sayHello(); // 我是半藏
genji.sayHello(); // 我是源氏 ES6的Object.assign() 和 ...展开运算符,但它们只能拷贝首层;数组中的 concat 和 slice 也可以实现,但它们也是拷贝首层 |
浅拷贝和深拷贝主要是用来区别拷贝引用类型的值的情况,浅拷贝直接拷贝引用类型的值的引用地址。深拷贝是拷贝引用类型的值对应的在堆内存中存储的值。 Object.assign(source, target), 以及对象展开操作符{...source}实现的是浅拷贝,JSON.parse(JSON.stringify(source))可以实现浅拷贝,但是对象必须是json安全的,比如无法识别undefined, 函数等 对象深拷贝的递归实现 function deepClone(obj) {
if (obj === null) return obj;
if (typeof obj !== 'object') return obj;
let copy = new obj.constructor();
for (let key in obj) {
copy[key] = deepClone(obj[key]);
}
return obj;
} |
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。 实现一个深拷贝 function clone(obj) {
var copy;
switch (typeof obj) {
case "undefined":
break;
case "number":
copy = obj - 0;
break;
case "string":
copy = obj + "";
break;
case "boolean":
copy = obj;
break;
case "object": //object分为两种情况 对象(Object)和数组(Array)
if (obj === null) {
copy = null;
} else {
if (object.prototype.toString.call(obj).slice(8, -1) === "Array") {
copy = [];
for (var i = 0; i < obj.length; i++) {
copy.push(clone(obj[i]));
}
} else {
copy = {};
for (var j in obj) {
copy[j] = clone(obj[j]);
}
}
}
break;
default:
copy = obj;
break;
}
return copy;
}
// 这段代码是去年刚入门的时候撸的 满满的槽点 哈哈哈哈 下面是浪里行舟大佬文章里的递归思路的函数,相较上面的那段考虑的更多更细致,感谢大佬的分享输出。
参考文章: |
深拷贝和浅拷贝是针对复杂数据类型来说的。 深拷贝
浅拷贝
可以使用 let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let obj2 = Object.assign({}, obj);
let obj3 = {...obj};
obj.name = 'Jack';
obj.hobbies.push('coding');
console.log(obj);//{ name: 'Jack', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj2);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj3);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
let arry = ['name', 'age', { info: 'female' }];
let arry2 = arry.slice(0);
let arry3 = arry.concat([]);
let arry4 = [...arry];
arry2[2].hi = 'hi';
console.log(arry2);//[ 'name', 'age', { info: 'female', hi: 'hi' } ]
console.log(arry3)//[ 'name', 'age', { info: 'female', hi: 'hi' } ]
console.log(arry4);//[ 'name', 'age', { info: 'female', hi: 'hi' } ] 可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。来看一下使用 let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let newObj = {};
for(let key in obj){
newObj[key] = obj[key];
//这一步不需要多说吧,复杂数据类型栈中存的是对应的地址,因此赋值操作,相当于两个属性值指向同一个内存空间
}
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
obj.age = 20;
obj.hobbies.pop();
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading' ] } 深拷贝实现
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let newObj = JSON.parse(JSON.stringify(obj));//newObj和obj互不影响
obj.hobbies.push('coding');
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
1.对象的属性值是函数时,无法拷贝。 let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography'],
sayHi: function() {
console.log(sayHi);
}
}
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] } 2.原型链上的属性无法获取 function Super() {
}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
this.name = name;
this.age = age;
}
Child.prototype = new Super();
let obj = new Child('Yvette', 18);
console.log(obj.location); //NanJing
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18}
console.log(newObj.location);//undefined;原型链上的属性无法获取
1.如果是基本数据类型,直接返回 function deepClone(obj) { //递归拷贝
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeof obj !== 'object') {
//如果不是复杂数据类型,直接返回
return obj;
}
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
let t = new obj.constructor();
for(let key in obj) {
//如果 obj[key] 是复杂数据类型,递归
if(obj.hasOwnProperty(key)){//是否是自身的属性
t[key] = deepClone(obj[key]);
}
}
return t;
} 测试: function Super() {
}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
Child.prototype = new Super();
let obj = new Parent('Yvette', 18, ['reading', 'photography']);
obj.sayHi = function () {
console.log('hi');
}
console.log(obj.location); //NanJing
let newObj = deepClone(obj);
console.log(newObj);//
console.log(newObj.location);//NanJing 可以获取到原型链上的属性
newObj.sayHi();//hi 函数属性拷贝正常 |
|
深拷贝和浅拷贝的区别 常见的浅拷贝的应用 常见的深拷贝应用
|
浅拷贝 深拷贝 区别: 深拷贝实现: (微信名:RUN) |
浅拷贝 和 深拷贝
|
// 浅拷贝 和深拷贝 // 对象的浅拷贝 function simpleClone(initObj){ // console.log(CloneObj.a) //修改拷贝后的值-对象浅拷贝-层 // es6的 Object.assign() 把多个目标拷贝到一个目标对象 拷贝的是对象的属性引用 而不是对象本身 也是只能拷贝一层 浅拷贝 CloneObj1.a = "修改原来的值assin拷贝" // 深拷贝 多层拷贝 var obj3 = { // 循环引用 把自己赋值给自己的一个属性 // 递归实现深拷贝 // ***如果是对象是 日期 正则的话 就需要特使处理了 |
|
浅拷贝
Object.assign
使用展开运算符 ...
for in
Array.prototype.slice()
Array.prototype.concat()
深拷贝
使用JSON.parse(JSON.stringify(obj))
简单深度拷贝
|
浅拷贝和深拷贝都只针对于引用数据类型。
浅拷贝:
1.深拷贝最简单的实现是: JSON.parse(JSON.stringify(obj))
看了几篇文章,还是感觉艳姐的递归方法,简单,完美实现各种情况,学到了,这个 new obj.constructor() 用的好巧妙, 厉害 |
深拷贝和浅拷贝的区别
function DeepCopy(obj) {
if(typeof obj !== 'object') return;
let newObj = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if(typeof obj[key] === 'Object') {
DeepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
}
return newObj;
} |
深拷贝和浅拷贝的区别是什么?如何实现一个深拷贝?深拷贝和浅拷贝的区别是什么?深拷贝和浅拷贝都是针对引用类型来说的。JS的类型可以分为基本类型(值类型)和引用类型,对基本类型的复制操作实际上是在栈内存重新开辟一个空间,用来存放基本类型的值,两个变量指向的是两个不同的内存空间,对引用类型的复制操作实际上也是在栈内存重新开辟一个空间,用来存放值,但是这个值是一个地址,导致两个变量最后指向的是还是同一个地址。
针对以上的引用类型的之间的复制问题,有时候不是我们想要的效果。 那么我们应该怎么使引用类型之间的复制不是复制地址呢?这就涉及到浅拷贝和深拷贝话题了。根据拷贝的层级不同可以分为浅拷贝和深拷贝,浅拷贝就是只进行一层拷贝,深拷贝就是无限层级拷贝 浅拷贝即只对第一层的对象进行拷贝。第二层或者往下的仍然还是拷贝地址
for..in 这种用法也就是遍历对象属性,把对象属性重新设置到新的对象上
如果对象是数组,可以使用数组的方法。
深拷贝即无限层级拷贝。 最简单的深拷贝就是浅拷贝+递归。递归条件就是判断一下是不是对象就可以了。
但是上述实现例子会存在几个问题
JS中的黑魔法,使用一行代码实现深拷贝
但是也会存在以下几个问题
最后附上颜海镜大大的文章。深拷贝的终极探索 |
深拷贝与浅拷贝的区别是什么?深拷贝和浅拷贝都是相对于引用类型而言。 var a = {
b: 1
}
var b = { ...a }
b.b = 2
a // {b: 2} 深拷贝理解起来也很简单,就是执行之后,新的变量无论怎么改动都不会影响原来的变量就对了 function baseClone(value, bitmask, customizer, key, object, stack) {
let result
const isDeep = bitmask & CLONE_DEEP_FLAG
const isFlat = bitmask & CLONE_FLAT_FLAG
const isFull = bitmask & CLONE_SYMBOLS_FLAG
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value)
}
if (result !== undefined) {
return result
}
if (!isObject(value)) {
return value
}
const isArr = Array.isArray(value)
const tag = getTag(value)
if (isArr) {
result = initCloneArray(value)
if (!isDeep) {
return copyArray(value, result)
}
} else {
const isFunc = typeof value == 'function'
if (isBuffer(value)) {
return cloneBuffer(value, isDeep)
}
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
result = (isFlat || isFunc) ? {} : initCloneObject(value)
if (!isDeep) {
return isFlat
? copySymbolsIn(value, copyObject(value, keysIn(value), result))
: copySymbols(value, Object.assign(result, value))
}
} else {
if (isFunc || !cloneableTags[tag]) {
return object ? value : {}
}
result = initCloneByTag(value, tag, isDeep)
}
}
// Check for circular references and return its corresponding clone.
stack || (stack = new Stack)
const stacked = stack.get(value)
if (stacked) {
return stacked
}
stack.set(value, result)
if (tag == mapTag) {
value.forEach((subValue, key) => {
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))
})
return result
}
if (tag == setTag) {
value.forEach((subValue) => {
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))
})
return result
}
if (isTypedArray(value)) {
return result
}
const keysFunc = isFull
? (isFlat ? getAllKeysIn : getAllKeys)
: (isFlat ? keysIn : keys)
const props = isArr ? undefined : keysFunc(value)
arrayEach(props || value, (subValue, key) => {
if (props) {
key = subValue
subValue = value[key]
}
// Recursively populate clone (susceptible to call stack limits).
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack))
})
return result
}
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)
} |
深拷贝与浅拷贝的区别是什么?js中的数据类型分为基本类型和引用类型。
针对引用类型我们就有了浅拷贝和深拷贝两种方法,它们区别在于对象的嵌套层级,浅拷贝就只能对第一层进行拷贝,深拷贝则可以通过JSON.parse(JSON.stringify(object)),递归(对多个层级进行类型判断依次执行对应类型的浅拷贝。 |
数组对象的深拷贝与浅拷贝
由上栗子可以看出 :原始数据类型赋值时,给的是实实在在的数据值 ,赋值后二者只是值一样而已,不会相互影响; 而对象类型,给的是 原数据的引用地址,所以新旧数据会互相影响,因为本质上还是同一个数据对象,如上栗中的数组 什么是浅拷贝?浅拷贝就是流于表面的拷贝方式;当属性值为对象类型时,只拷贝了对象数据的引用,导致新旧数据没有完全分离,还会互相影响
栗子中 array2是array1的浅拷贝对象,数组元素是原始数据类型的不会相互影响了(array1[0]),但是array1[3]是对象类型,还是会互相影响。 深拷贝及其实现从浅拷贝解释基本可以明白,深拷贝就是 ‘完全’拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会互相影响。
总结一定要理解造成浅拷贝的原因:对象类型数据复制时,复制了引用地址,用的还是同一个数据对象;所以实现深拷贝的方式就是要对 对象类型属性值递归进行深拷贝,避免直接赋值。 |
首先要明白, 对于复杂类型而言,一个对象创建的时候会在内存中分配两块空间,一个在栈内存中存储对象的引用指针,一个在堆内存中存储对象真实的数据。这时候会有一个问题,你拷贝的只是这个引用指针,还是连同它的真实数据一起拷贝,所以才会有深浅拷贝一说。 =赋值当我们把一个对象赋值给一个新的变量时,赋的其实是该对象在栈中的引用地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
上面代码说明了 浅拷贝在了解到
要实现 可以使用
通过这个例子,可以很清楚的知道 我们在上面代码的基础上再做一下修改:
上面的代码说明: 这时候就需要使用 深拷贝简单理解就是:可以实现多层数据的拷贝,拷贝后的对象是一个全新独立的对象,重新为其分配内存空间,跟原对象不会相互影响。 使用 JSON.parse(JSON.stringify(obj))实现
但是该方法也是有局限性的(来自某大佬的小册内容):
可以看到,上述情况中,
如果你有这么一个循环引用对象,你会发现并不能通过该方法实现
上面代码说明: 实际开发中,可以直接使用
总结
参考: |
深拷贝: let deepclone = function(obj) {
let res
if(typeof obj == "object") {
res = Array.isArray(obj) ? [] : {}
for(let i in obj) {
res[i] = typeof obj[i] === "object" ? deepclone(obj[i]) : obj[i]
}
} else {
res = obj
}
return res
} |
深拷贝与浅拷贝的慨念划分主要是复杂类型的赋值引发的。 由于复杂类型(array/object)存储于内存中。而JavaScript不允许直接从内存中操作数据。所以js贴心的给了你一张房卡。 所以,复制房卡的是浅拷贝。 |
深拷贝与浅拷贝的区别?如何实现一个深拷贝 在回答这个问题前,我们先来回顾一下JS中两大数据类型 基本类型 Undefined、Null、Boolean、Number、String 引用类型 let obj = { let obj = { |
深拷贝和浅拷贝的区别深拷贝是对对象以及对象的所有子对象进行拷贝,和原数据没有指向同一个对象,如果第一层为基本数据类型,改变不会使原数据一同改变,如果原数据中包含子对象,改变不会使原数据一同改变。 浅拷贝和原数据没有指向同一个对象,如果第一层为基本数据类型,改变不会使原始数据一同改变,如果原数据中包含子对象,改变会使原数据一同改变。 实现一个深拷贝/**
* target 目标对象 对象都合并到target里
* source 合并对象
*/
function deepClone(target, source) {
for (key in source)
if ((isPlainObject(source[key]) || isArray(source[key]))) {
// source[key] 是对象,而 target[key] 不是对象, 则 target[key] = {} 初始化一下,否则递归会出错的
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {}
// source[key] 是数组,而 target[key] 不是数组,则 target[key] = [] 初始化一下,否则递归会出错的
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
// 执行递归
extend(target[key], source[key])
}
// 不满足以上条件,说明 source[key] 是一般的值类型,直接赋值给 target 就是了
else if (source[key] !== undefined) target[key] = source[key]
} |
针对引用类型(对象、数组) 浅拷贝浅拷贝一个对象,如果属性是基本数据类型,直接拷贝值,若新的对象属性值改变,不会改变原来的属性值。但是对于引用类型的数据,只是拷贝了该对象的地址,与原对象指向同一个地址,若新的对象改变,会影响原来的对象。 深拷贝深拷贝一个对象,除了拷贝基本数据类型的值,会递归拷贝所有引用类型,所有引用类型都会指向一个新的内存地址。与原来的对象完全隔离,新的对象的改变不会影响原来的对象。
缺点:
|
No description provided.
The text was updated successfully, but these errors were encountered: