克隆/复制地图实例


88

如何在JavaScript中克隆/复制地图?

我知道如何克隆数组,但是如何克隆/复制地图?

var myArray = new Array(1, 2, 3);
var copy    = myArray.slice();
// now I can change myArray[0] = 5; & it wont affect copy array

// Can I just do the same for map?
var myMap = new ?? // in javascript is it called a map?
var myMap = {"1": 1, "2", 2};
var copy  = myMap.slice(); 

2
ES6让您let copy = {...myMap};
Reactgular

Answers:


17

一种简单的方法(进行浅表复制)是将源映射的每个属性复制到目标映射:

var newMap = {};
for (var i in myMap)
   newMap[i] = myMap[i];

注意:newMap [i]很可能是对与myMap [i]相同对象的引用


6
这只是一个浅表副本...如果myMap [i]本身是地图怎么办?
Stefano

1
Stefano,可以根据需要执行此操作(检查是否为typeof对象,然后执行其属性的副本...可能通过递归相同的函数),但是请记住,现在您必须关注他们成为祖先元素的可能性,这会使您陷入无限循环。如果您确实想要一个深层副本,则可能需要研究库来完成。
2012年

4
我知道,但是我认为您应该首先在答案中写上这句话;-)
Stefano

5
这不是地图,而是对象。细微差别。cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
暂停

1
它不会复制您将无法使用设置程序和获取程序的所有属性,而只是将其作为对象
Amante Ninja

329

随着JavaScript中Maps的引入,考虑到构造函数接受可迭代,这非常简单:

var newMap = new Map(existingMap)

此处的文档:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map


4
上面的一个小警告:克隆这样的地图将调用Map.prototype.entriesMap.prototype.set。这意味着:如果您编写一个扩展Map覆盖这两个方法之一的类,那么new ExtendedMap( extendedMapObj )如果扩展方法依赖于上级不可用的属性,则无法简单地编写代码。

它是深克隆还是浅克隆?假设我已将对象嵌套为值
Madeo

但这会做深层复制还是浅层复制?
Yonatan Nir

5
这将做一个浅表复制,而不是深表复制:jsfiddle.net/jormwe69
Jaap

1
@PeterCoester我们可以说的渐近var newMap = new Map(existingMap)O(n)哪里n的地图的键/值对的数目?我猜想,O(1)如果像您所说的那样 Map.prototype.entries
后台

11

克隆地图非常简单,因为您所谈论的只是一个对象。MapES6中有一个您应该查找的,但是要复制一个对象,只需使用Object.assign()

let map = {"a": 1, "b": 2}
let copy = Object.assign({}, map);

您也可以cloneDeep()从Lodash使用

let copy = cloneDeep(map);

6

jQuery具有扩展对象(合并两个对象)的方法,但是该方法也可以通过提供空对象来克隆对象。

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

可以在jQuery文档中找到更多信息。


3

没有内置的东西。

请使用经过良好测试的递归属性复印机,或者如果性能不成问题,请序列化为JSON并再次解析为新对象。


2

没有内置的克隆/副本。您可以编写自己的方法来浅拷贝或深拷贝:

function shallowCopy(obj) {
    var result = {};
    for (var i in obj) {
        result[i] = obj[i];
    }
    return result;
}

function deepCopy(obj) {
    var result = {};
    for (var i in obj) {
        // recursion here, though you'll need some non-trivial logic
        // to avoid getting into an endless loop.
    }
    return result;
}

Javascript中的所有对象都是动态的,可以分配新的属性。您所指的“地图”实际上只是一个空对象。Array也是一个对象,具有诸如slice和属性之类的方法length


不明白您编写的两个函数有什么区别!
哈桑·优素福

@HasanAYousef差异未实现;在深层复制中,您必须递归(为每个子代调用deepCopy),但是由于子代可能包含对父代的引用(例如window.window2 = window),因此,如果不进入无限循环,就无法深度复制这些引用。
妮可

2

如果您需要复制地图的深层副本,可以使用以下方法:

new Map(JSON.parse(JSON.stringify(Array.from(source))));

source原始Map对象在哪里。

请注意,这可能不适用于Map值不可序列化的所有用例,有关更多详细信息,请参见:https : //stackoverflow.com/a/122704/10583071


我对jsperf进行了测试,发现迭代方法的速度提高了10倍:jsperf.com/deep-copy-map
Zack Burt

2
@ZackBurt遗憾的是,您提出的更快的替代方案并没有真正创建deep copy目标Map,而只是创建了一个目标shallow copy。也许这就是为什么它这么快吗?
阿方索·M·加西亚·阿斯托加

@AlfonsoM.GarcíaAstorga感谢您的澄清(相应支持)。您是正确的,因为它不是深层副本。但这是更快的副本,具有<10kb的数据。推荐补充阅读:v8.dev/blog/cost-of-javascript-2019#json
扎克伯特

1

我注意到Map应该需要特殊对待,因此在该线程中的所有建议下,代码将是:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.