-
Notifications
You must be signed in to change notification settings - Fork 634
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
百度:什么是浅拷贝和深拷贝?有什么区别?如何实现 Object 的深拷贝 #55
Comments
解答在js中,对象是引用类型。如果给一个变量赋值给一个对象的时候,这时候变量和对象都是指向同一个引用,即 let obj1 = {a: 1}
let obj2 = obj1
console.log(obj2.a) // 1
obj2.a = 2
console.log(obj2.a) // 2
console.log(obj1.a) // 2 由于指向的是同一个引用,即 但是我们希望说不想要这种效果,那么就可以使用 浅拷贝 来实现,这样和原对象不是指向同一个引用,但是也会把对象的成员复制过来。 但是,浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就要使用到 深拷贝 了 深拷贝的实现1. JSON.parse(JSON.stringify(object))通常可以使用 let obj1 = {
a: 1,
b: {
c: 2
}
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.b.c = '3'
console.log(obj1.b.c) // 2 但是使用
2. 递归遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深拷贝 // 递归判断是否对象和数组
function deepClone(obj, target) {
if(!obj) return
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
if(Array.isArray(key) || (typeof obj[key] === 'object' && obj[key] !== null)) {
target[key] = []
deepClone(obj[key], target[key])
} else {
target[key] = obj[key]
}
}
}
return target
} |
浅拷贝的复制了指向对象的指针, 地址和原对象的地址指向相同 浅拷贝 function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
return c;
} 深拷贝 function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result, targetType = checkedType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === 'Object' ||
checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = clone(value)
} else { //获取到value值是基本的数据类型或者是函数。
result[i] = value;
}
}
return result
} |
基本类型和引用类型存储方式JavaScript中有两种类型,分别是基本类型和引用类型。其中基本类型就包括Number、String、Boolean、null、undefined、Symbol、BigInt这几种,剩下的(Array、Regex、Object、Function等等)都是引用类型。通常我们创建这两种类型的值之后会使用一个变量来保存它,而对于基本类型的值我们是直接使用对象保存它的值,对于引用类型的值,我们是保存它的引用(在C语言里就是指针,即内存地址) let number = 1
let string = 'abc'
let object = { name: 'luwei' } 上面声明了三个变量,其中
拷贝方式基本类型的拷贝方式let number = 1
let string = 'abc'
let number2 = number
let string2 = string
number2 = 3
string2 = 'dcba'
console.log(number, number2) // 1 , 3
console.log(string, string2) // 'abc' , 'dcba'
引用类型的拷贝方式通过上文的描述,我们知道引用类型的值是保存在堆空间的,而保存引用类型的变量,其实是存在于栈空间的,它保存着引用类型的值在堆空间的内存地址。那么我们要拷贝引用类型的值就会出现两种情况 浅拷贝所谓浅拷贝就是使用一个变量去拷贝一个引用类型在栈中的内存地址 let object = { name: 'luwei' }
let object2 = object
object2.name = 'LUWEI'
console.log(object) // { name: 'LUWEI' } 深拷贝而深拷贝就是指在堆空间中,另外开辟出一个空间,并把原有的堆空间中保存的引用类型的值拷贝到新的空间中来。 let object = { name: 'luwei' }
let object2 = JSON.parse(JSON.stringify(object))
object2.name = 'LUWEI'
console.log(object) // { name: 'luwei' } 实现深拷贝的方式第一种:
|
const fun = (input) => {
if(typeof input !== 'object') return input
if(input instanceof Array) {
return input.map(val=>fun(val))
}
if(input instanceof Object) {
const obj = {}
for(val in input){
obj[val] = fun(input[val])
}
return obj
}
} |
@luweiCN |
/**
* 实现深拷贝需要注意的点:
*/
const parent = {
a: 1,
b: 2,
c: 3
}
const child = {
d: 4,
e: 5,
[Symbol()]: 6
}
child.__proto__ = parent
Object.defineProperty(child, "d", { enumerable: false })
console.log("Object.keys()>>>>>", Object.keys(child))//Object.keys()>>>>> [ 'e' ]
console.log("Object.getOwnPropertyNames>>>>",Object.getOwnPropertyNames(child))//Object.getOwnPropertyNames>>>> [ 'd', 'e' ]
console.log("Reflect.ownKeys>>>>",Reflect.ownKeys(child))//Reflect.ownKeys>>>> [ 'd', 'e', Symbol() ]
/**
* 3. 使用递归
* 获取属性for in
* Object.keys(obj)
* Object.getOwnPropertyNames(obj)
* Reflect.ownKeys
* 以上几种方法的区别
*/
function deepClone(oldObj) {
let newObj = Array.isArray(oldObj)?[]:{};
for(let key in oldObj) {
if(oldObj.hasOwnProperty(key)) {
if(oldObj[key]&&typeof oldObj[key]==='object') {
console.log('进入深拷贝')
newObj[key] = deepClone(oldObj[key]);
} else {
newObj[key] = oldObj[key];
}
}
}
return newObj;
}
let newObj3 = deepClone(oldObj); |
/**
* 引用类型会有深拷贝的问题
* 如果是引用类型数据,为了不改动原始数据需要深拷贝原数据
*/
/**
* 1. 使用工具lodash函数库
* let newObj = _.cloneDeep(oldObj);
*/
let oldObj = {
'a':{
'name':'消防',
'age':22
},
'b':'b',
'c':{
'value':'hello',
'id':23
},
'd':[1,2,3],
'fun':function(){}
}
/**
* 2. 使用JSON对象
* 用JSON.stringify将对象转换为JSON字符串然后拷贝
* 但是JSON.stringify不能转换函数即不能拷贝对象的方法
*/
function deepCopy(oldObj) {
let newObj = JSON.parse(JSON.stringify(oldObj));
return newObj;
}
let newObj2 = deepCopy(oldObj);
console.log('newObj2: ', newObj2);//{ a: { name: '消防', age: 22 }, b: 'b', c: { value: 'hello', id: 23 } }
oldObj['c']['id'] = 333;
console.log('newObj2: ', newObj2);//{ a: { name: '消防', age: 22 }, b: 'b', c: { value: 'hello', id: 23 } }
console.log('oldObj:>>>',oldObj)//{ a: { name: '消防', age: 22 }, b: 'b', c: { value: 'hello', id: 333 } }
/**
* 实现深拷贝需要注意的点:
*/
const parent = {
a: 1,
b: 2,
c: 3
}
const child = {
d: 4,
e: 5,
[Symbol()]: 6
}
child.__proto__ = parent
Object.defineProperty(child, "d", { enumerable: false })
console.log("Object.keys()>>>>>", Object.keys(child))//Object.keys()>>>>> [ 'e' ]
console.log("Object.getOwnPropertyNames>>>>",Object.getOwnPropertyNames(child))//Object.getOwnPropertyNames>>>> [ 'd', 'e' ]
console.log("Reflect.ownKeys>>>>",Reflect.ownKeys(child))//Reflect.ownKeys>>>> [ 'd', 'e', Symbol() ]
/**
* 3. 使用递归
* 获取属性for in
* Object.keys(obj)
* Object.getOwnPropertyNames(obj)
* Reflect.ownKeys
* 以上几种方法的区别
*/
function deepClone(oldObj) {
let newObj = Array.isArray(oldObj)?[]:{};
for(let key in oldObj) {
if(oldObj.hasOwnProperty(key)) {
if(oldObj[key]&&typeof oldObj[key]==='object') {
console.log('进入深拷贝')
newObj[key] = deepClone(oldObj[key]);
} else {
newObj[key] = oldObj[key];
}
}
}
return newObj;
}
let newObj3 = deepClone(oldObj);
console.log(newObj3);
oldObj['c']['id'] = 55;
oldObj['d'][0] = 22;
console.log('更改原对象之后newObj',newObj3);
//{
// a: { name: '消防', age: 22 },
// b: 'b',
// c: { value: 'hello', id: 333 },
// fun: [Function: fun]
// }
console.log('更改原对象之后oldObj',oldObj)
// {
// a: { name: '消防', age: 22 },
// b: 'b',
// c: { value: 'hello', id: 55 },
// fun: [Function: fun]
// } |
No description provided.
The text was updated successfully, but these errors were encountered: