javascript的傳參都是引用傳遞。下面的代碼
function mutate(obj) {
obj.a = true;
}
const obj = {a: false};
mutate(obj)
console.log(obj.a);
答案:1: prints true 2: prints false
正確答案是1.因?yàn)檫@里正是通過(guò)引用來(lái)傳參的。
那么下面這樣是否可以呢?答案已經(jīng)已經(jīng)可以看到了,這里的Object.assign是一種淺拷貝,對(duì)于obj里面還有嵌套的對(duì)象時(shí),一樣存在引用傳遞的問(wèn)題
const obj = /* ... */;
const copy = Object.assign({}, obj);
function mutateDeepObject(obj) {
obj.a.thing = true;
}
const obj = {a: {thing: false}};
const copy = Object.assign({}, obj);
mutateDeepObject(copy)
console.log(obj.a.thing); // prints true
還有object.spread同樣是創(chuàng)建一個(gè)淺拷貝
當(dāng)然,有時(shí)你可能想要完全拷貝一個(gè)對(duì)象,作為參數(shù)去傳遞,從而不影響原有的對(duì)象。下面是介紹幾種深拷貝的例子
1,json.parse
const obj = /* ... */;
const copy = JSON.parse(JSON.stringify(obj));
怎么樣,可能你曾用過(guò),這里就是深拷貝的引用。
但是對(duì)Maps, Sets, RegExps, Dates, ArrayBuffers等不適用。
- MessageChannel
function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}
const obj = /* ... */;
const clone = await structuralClone(obj);
這里的消息對(duì)象 obj接收方就是一個(gè)深拷貝對(duì)象.這里是一種異步深拷貝。下面的state則是同步深拷貝的應(yīng)用
3.History API
function structuralClone(obj) {
const oldState = history.state;
history.replaceState(obj, document.title);
const copy = history.state;
history.replaceState(oldState, document.title);
return copy;
}
const obj = /* ... */;
const clone = structuralClone(obj);
這里的 state每次都是一次深拷貝.(safari限制30ms內(nèi)最多調(diào)用100次)
4.Notification API
function structuralClone(obj) {
return new Notification('', {data: obj, silent: true}).data;
}
const obj = /* ... */;
const clone = structuralClone(obj);
這種方式受瀏覽器權(quán)限限制,會(huì)比較慢。由于某些原因safari會(huì)返回 undefined
總結(jié):實(shí)際中使用時(shí),可以優(yōu)先使用
1,JSON.parse(JSON.stringify())性能最佳且各支持種瀏覽器
2.MessageChanne 支持各種瀏覽器