浅克隆Map或Set

170

如何在JavaScript中进行浅克隆一个MapSet对象?

我想获得一个新的Map或Set,其中包含相同的键和值。

6个回答

314
使用构造函数来克隆地图和集合:
let clonedMap = new Map(originalMap);

let clonedSet = new Set(originalSet);

4
如何进行深度克隆? - BILL
4
请查看这个 JSFiddle 示例来了解如何深度克隆一个 Map:https://jsfiddle.net/pahund/5qtt2Len/1/ - Patrick Hund
7
Map 应该被视为抽象数据类型,而不是 JavaScript 对象。因此深度克隆一个 Map 没有意义。 - user6445533
6
很遗憾,在 IE 11 中拷贝构造函数无法正常工作(会创建一个空的映射)。 - Jan Molnár

14

浅克隆:

var clonedMap = new Map(originalMap)

var clonedSet = new Set(originalSet)

深度克隆:

var deepClonedMap = new Map(JSON.parse(JSON.stringify([...originalMap])))
var deepClonedSet = new Set(JSON.parse(JSON.stringify([...originalSet])))

let originalMap = new Map()
let data = {a:'a',b:'b'}
originalMap.set(1,data)

let shallowCloned = new Map(originalMap)
let deepCloned = new Map(JSON.parse(JSON.stringify([...originalMap])))
data.a = 'p'
console.log('originalMap:',[...originalMap])
console.log('shallowCloned:',[...shallowCloned])
console.log('deepCloned:',[...deepCloned])


如果originalMap里面还有其他的map/set,我猜这个方法就不会起作用了。 - Dmitry Koroliov
提醒:parse/stringify方法仅适用于原始值(字符串、数字、布尔值)。如果你有BigInt、Date、函数等等,它将会出错。 - targumon

12

使用 for 循环创建新 Set 对象比使用 Set 构造函数更快。对于 Map 对象也是一样(虽然程度较小)。

const timeInLoop = (desc, loopCount, fn) => {
  const d = `${desc}: ${loopCount.toExponential()}`
  console.time(d)
  for (let i = 0; i < loopCount; i++) {
    fn()
  }
  console.timeEnd(d)
}

const set = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

const setFromForLoop = x => {
  const y = new Set()
  for (const item of x) y.add(item)
  return y
}

const map = new Map([['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5]])

const mapFromForLoop = x => {
  const y = new Map()
  for (const entry of x) y.set(...entry)
  return y
}

timeInLoop('new Set(set)', 1e5, () => new Set(set))

timeInLoop('setFromForLoop(set)', 1e5, () => setFromForLoop(set))

timeInLoop('new Map(map)', 1e5, () => new Map(map))

timeInLoop('mapFromForLoop(map)', 1e5, () => mapFromForLoop(map))


4
不错的发现!可能值得在Chromium bug跟踪器上创建一个bug,以引起他们的注意。这个问题肯定可以在引擎中修复。同样地,对于Firefox也是如此,其对“Set”(但不是“Map”)展示了相同的问题。 - Jo Liss
1
有趣的是,在Safari中,new Set(set)setFromForLoop(set)快大约15-20毫秒,但在Chrome中,setFromForLoop(set)new Set(set)快大约20-28毫秒。 - Magne
12
对于年轻的开发者来说,这是一则有趣但危险的信息。除非你现在绝对需要最快的速度,否则最好使用构造函数方法,因为正如@JoLiss指出的那样,这是一个错误,将被修复 - 这是别人的问题,所以你写的代码越少越好! - AntonOfTheWoods
1
通常情况下,如果没有充分的理由,担心性能问题是一个非常糟糕的想法。优先考虑最小化开发时间,否则你最终会变得效率低下,却没有任何回报。 - ICW
非常适用于需要提高页面加载等性能的人,尽管我不认为自己会创建10000个集合。 - SoluableNonagon
@AntonOfTheWoods 说得好,但你可以添加一个 cloneSet() 函数,并在文档中说明为什么要使用它而不是 Set 构造函数,或者简单地提供一个链接到这个答案。 - Amit Beckenstein

0
这种方式需要的浅拷贝代码最少,可以完成任务。
披露:我没有测试过这种方式是否会影响性能,在大型数据集或者有很多数据集的情况下,可能不是最佳选择。
const mySet = new Set([1, 2, 3, 4]);
const myCloneSet = new Set(Array.from(mySet));
console.log(mySet === myCloneSet) //false

-1

我需要复制(“克隆”)一个JavaScript集,而这个问题引起了我的兴趣,关于那个克隆副本的完整性,对于那些副本的源发生扰动。

测试

var fruit = new Set(['apples', 'bananas']);
var provinces = new Set(['british columbia', 'nova scotia']);
console.log('fruit:', fruit)
console.log('provinces:', provinces)
// fruit: Set [ "apples", "bananas" ]
// provinces: Set [ "british columbia", "nova scotia" ]

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#implementing_basic_set_operations
function unionSets(setA, setB) {
    let _union = new Set(setA);
    for (let elem of setB) {
        _union.add(elem)
    }
    return _union;
}

myUnionSet = unionSets(fruit, provinces);
console.log('myUnionSet:', myUnionSet)
// myUnionSet: Set(4) [ "apples", "bananas", "british columbia", "nova scotia" ]

// Tests:
fruit.delete('apples');
provinces.delete('british columbia');

console.log('fruit:', fruit)
console.log('provinces:', provinces)
console.log('myUnionSet:', myUnionSet)
// fruit: Set [ "bananas" ]
// provinces: Set [ "nova scotia" ]
// myUnionSet: Set(4) [ "apples", "bananas", "british columbia", "nova scotia" ]

-2
如果Map包含非嵌套结构(例如数组的Map),这里有一个快速的深拷贝方法,供有兴趣的人参考:
const newMap = new Map();
old.forEach((val, key) => newMap.set(key, [...old.get(key)]));

OP 要求进行浅克隆。 - Bergi
当然可以,但是如果你看评论区,有些人在寻找深度克隆的方法。我也是,但是没有找到我需要的答案,所以我为可能感兴趣的人添加了一个答案。 - Hung Vu Dinh
顶部的答案很好,所以我不需要重复相同的事情。 - Hung Vu Dinh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接