开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天
javascript中数据类型分为基本数据类型和引用数据类型,复制基本数据类型会在栈中开辟新的空间,将变量指向新值,新旧变量互不影响。复制引用数据类型时候,也是在栈中开辟新的空间,这个栈中存的是地址,新旧地址指向堆中的同一个实体,两者会相互影响。
浅拷贝:拷贝的对象指针,不复制对象本身,新旧对象共享同一块内存,互相影响。 深拷贝:拷贝对象本身,开辟新地址,新旧对象不共享,互不影响。 拷贝数组只有一层时候是深拷贝
一、浅拷贝
创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回。
let source = {a:1}
function clone(source){
let target = {};
for(let i in source){
if(source.hasOwnProperty(i)){
target[i]=source[i]
}
}
return target
}
let target = clone(source)
Object.assign({},source)
var _ = require('lodash')
; var target = _.clone(source);
let target= {... source}
let target = source.concat();
let target = source.slice();
当原数据Array只有一层的时候,是深拷贝;所以当原数据进行浅拷贝,改变arr2的arr[1],而原数据arr1中的arr1[1]没有改变;
二、深拷贝
let target = JSON.parse(JSON.stringify(source));
利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了
var _ = require('lodash'); var target = _.cloneDeep(source);
V 1.0
原始类型直接返回、引用类型创建新对象,递归至基本数据类型为止、考虑数组情况
function clone(target)
{
if (typeof target === 'object')
{
let cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target)
{
cloneTarget[key] = clone(target[key]);
}
return cloneTarget;
}
else
{
return target;
}
};
V 2.0循环引用
V 3.0考虑其他数据类型
三、=、浅拷贝、深拷贝区别
针对引用数据类型
赋值:拷贝的是栈中的地址,不是堆中的数据,新旧地址指向同一个存储空间,不管是基本类型还是引用类型都互相影响。
// 对象赋值
let obj1 = { name : 'js', arr : [1,[2,3],4], };
let obj2 = obj1;
obj2.name = "node"; obj2.arr[1] =[5,6,7] ;
console.log('obj1',obj1) // obj1 { name: 'node', arr: [ 1, [ 5, 6, 7 ], 4 ] } console.log('obj2',obj2) // obj2 { name: 'node', arr: [ 1, [ 5, 6, 7 ], 4 ] }
浅拷贝:在堆中创建新内存,拷贝前后若是基本类型互不影响,若是引用类型因共享同一块内存,会相互影响。
// 浅拷贝:name互不影响,arr相互影响
let obj1 = {
name: 'js',
arr: [1, [2, 3], 4],
};
let obj3 = shallowClone(obj1)
obj3.name = "node";
obj3.arr[1] = [5, 6, 7]; // 新旧对象共享同一块内存
// 这是个浅拷贝的方法
function shallowClone(source) {
var target = {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
console.log('obj1', obj1)
console.log('obj3', obj3)
深拷贝:从堆内存中创建新内存存放新对象,对对象中的子对象进行递归拷贝,互不影响。
// 深拷贝
let obj1 = { name : '浪里行舟', arr : [1,[2,3],4], };
let obj4=deepClone(obj1) obj4.name = "阿浪"; obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存 // 这是个深拷贝的方法
function deepClone(obj)
{
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== "object") return obj;
let cloneObj = new obj.constructor();
for (let key in obj)
{
if (obj.hasOwnProperty(key))
{
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key]);
} }
return cloneObj;
}
console.log('obj1',obj1) // obj1 { name: '浪里行舟', arr: [ 1, [ 2, 3 ], 4 ] } console.log('obj4',obj4) // obj4 { name: '阿浪', arr: [ 1, [ 5, 6, 7 ], 4 ] }
总结:
基本数据类型:赋值互相影响,浅拷贝深拷贝不影响
引用数据类型,赋值 浅拷贝互相影响,深拷贝不影响