在 JavaScript 中,拷贝是将一个对象的值复制到另一个对象的过程。JavaScript 中的拷贝可以分为浅拷贝和深拷贝两种类型。
- 浅拷贝(Shallow Copy):
- 通过方法把某个对象完整拷贝后,原对象的修改会影响新对象
- 常见的浅拷贝方法:
- Object.create(obj)
- Object.assign({},obj)
-
\].concat()
- arr.toReversed().reverser()(一种很新的内置函数,我浏览器不行)
-
深拷贝(Deep Copy):
- JSON.parse(JSON.stringify(obj))
但是这个方法有缺陷:
-
不能处理 undefined,function,Symbol
-
无法处理循环引用
- JSON.parse(JSON.stringify(obj))
学习拷贝前我们先来看看一段代码
js
let a={
age:18
}
let b=a
a.age=19
console.log(b.age); //19
会输出19是因为v8引擎会创建一个堆,用来存储引用类型,let b=a
只是把对象a在堆里的地址赋值给了b,更改了age的值,b的值也会更改,这算浅拷贝。
那看完考考你:
js
let a={
age:18
}
let b=a
a={
age:20
}
console.log(b.age); //输出??
第五段代码的a是 新的对象,所有地址不一样,前面a的地址会指向新对象,b地址不变。输出18。
浅拷贝
Object.create(obj)
js
let a={
name:'雨程',
like:{
n:'coding'
}
}
let b=Object.create(a)
a.name ='涛'
a.like.n='run'
console.log(b.like);// { n: 'run' }
console.log(b.name);//涛
使用Object.create(obj)把对象完整拷贝后,原对象的修改会影响新对象。
Object.assign({},obj)
js
let a={
name:'雨程',
like:{
n:'coding'
}
}
let b =Object.assign({},a) //拷贝了a的like的地址
a.like.n='run'
console.log(b.like); //'run'
这里同上
[].concat()
js
let arr=[1,2,3,{n:10}]
let newArr=[].concat(arr)
arr[3].n=100
console.log(newArr); //[ 1, 2, 3, { n: 100 }
数组里面原始值无法改变,对象会被改变
解构
js
let newArr=[...arr]
arr[3].n=100
console.log(newArr);//[ 1, 2, 3, { n: 100 } ]
浅拷贝函数
如果要你写个浅拷贝函数怎么办?
js
let obj={
name:'刘涛',
age:18,
like:{
n:'run'
}
}
// let o =Object.create(obj)
// o.sex='boy'
function shalldowCopy(obj){
//不是引用类型就不拷贝
if(!(obj instanceof Object))return;//if(typeof obj!=='object'||obj ==null) return
//如果obj是数组,就创建数组,是对象就创建对象
let objCopy=obj instanceof Array?[]:{}
for(let key in obj){
if(obj.hasOwnProperty(key)){
objCopy[key]=obj[key]
}
}
return objCopy
}
let newObj=shalldowCopy(obj)
console.log(newObj);
深拷贝
JSON.parse(JSON.stringify(obj))
js
let obj ={
name:'李总',
age:18,
a:{
n:1
},
b:undefined,
c:null,
d:Symbol(123),
e:function(){},
f:{
n:100
}
}
console.log(JSON.stringify(obj));//把对象转换成字符串,花括号也转换成字符串
let str = JSON.stringify(obj)
console.log(JSON.parse(str));
// let obj2 =JSON.parse(JSON.stringify(obj)) //深拷贝 但是需要注意
// obj.age=20
// obj.age.n=10
// console.log(obj2);
上方代码注释部分无法改变对象obj里面的任何值,不能处理 undefined,function,Symbol,无法输出。还无法处理循环引用
js
//上方代码加上这一段
obj.e=obj.f
obj.f.n=obj.e//循环引用
console.log(obj);//打印下方
//{
name: '李总',
age: 18,
a: { n: 1 },
b: undefined,
c: null,
d: Symbol(123),
e: <ref *1> { n: [Circular *1] },
f: <ref *1> { n: [Circular *1] }
}
深拷贝函数
js
function deepCopy(obj) {
let objCopy = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 区分 obj[key] 原始类型和引用类型
if (obj[key] instanceof Object) { // 不能直接赋值
objCopy[key] = deepCopy(obj[key]);////遇到对象里的对象就执行递归,遍历里面对象的属性,遍历完回去
} else {
objCopy[key] = obj[key]
}
}
}
return objCopy
}
let obj2 = deepCopy(obj);
obj.a.n = 11
console.log(obj2);
下方是介绍拷贝出现的方法
Object.assign
Object.assign是JavaScript中常用的一个方法,它可以将一个或多个源对象的属性复制到目标对象中。具体来说,它接受一个目标对象和一个或多个源对象作为参数,然后将所有源对象中的可枚举属性复制到目标对象中,并返回目标对象。
它的语法如下所示:
Copy
Object.assign(target, ...sources)
其中,target是目标对象,sources是一个或多个源对象。需要注意的是,如果多个源对象中有相同的属性名,则后面的属性值会覆盖前面的属性值。
除了复制属性外,Object.assign还有一些其他的用途。例如,我们可以使用它来合并多个对象:
Copy
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };
const mergedObj = Object.assign({}, obj1, obj2, obj3);
// mergedObj = { a: 1, b: 2, c: 3 }
把所有东西放到空对象,这样第一个对象就不会变
如果去掉空对象:
console.log(obj1);//{ a: 1, b: 2, c: 3 }
console.log(obj2);//{ b: 2 }
在上面的例子中,我们使用了三个源对象obj1、obj2和obj3,将它们的属性合并到一个新的空对象中,并将结果赋给mergedObj。
hasOwnProperty
hasOwnProperty
是 JavaScript 中的一个方法,用于检查对象自身是否包含指定名称的属性。它是从 Object
原型继承而来的方法。这个方法接受一个参数,即要检查的属性名称,如果对象本身具有该属性,并且不是通过原型链继承而来的,就会返回 true
,否则返回 false
。
例如:
javascriptCopy
let obj = {
name: 'Alice',
age: 25
};
console.log(obj.hasOwnProperty('name')); // 输出 true,因为 'name' 是对象 obj 自身的属性
console.log(obj.hasOwnProperty('toString')); // 输出 false,因为 'toString' 是从原型链继承而来的属性
hasOwnProperty
对于检查对象自身的属性非常有用,特别是当你想知道某个属性是不是对象自己创建的,而不是继承得来的时候。
JSON.stringify()
JSON.stringify()
是 JavaScript 中一个非常有用的函数,用于将 JavaScript 对象转换为 JSON 字符串。这个函数接受一个 JavaScript 对象作为参数,并返回对应的 JSON 字符串表示。
例如:
javascriptCopy
let obj = {
name: 'Alice',
age: 25,
interests: ['programming', 'reading']
};
let jsonString = JSON.stringify(obj);
console.log(jsonString);
这将输出类似于以下格式的 JSON 字符串:
css
jsonCopy code
{"name":"Alice","age":25,"interests":["programming","reading"]}
JSON.stringify()
还可以接受两个额外的参数,用于更进一步的控制转换过程:
- 第二个参数是一个 replacer 函数或者一个数组,用于选择性地过滤和转换结果。这允许你在生成 JSON 字符串时选择性地排除或转换某些属性。
- 第三个参数是一个 space 参数,用于添加缩进、空格或换行符,使输出的 JSON 字符串更易读。
这个函数通常在需要将 JavaScript 对象转换为可以传输、存储或与其他编程语言交互的字符串时非常有用。