合并ES6地图/布景的最简单方法?

2022-08-30 00:22:16

有没有一种简单的方法将ES6地图合并在一起(如)?当我们在它的时候,ES6套装(比如)呢?Object.assignArray.concat


答案 1

对于套装:

var merged = new Set([...set1, ...set2, ...set3])

对于地图:

var merged = new Map([...map1, ...map2, ...map3])

请注意,如果多个地图具有相同的键,则合并地图的值将是具有该键的最后一个合并地图的值。


答案 2

由于我不明白的原因,您不能使用内置方法将一个 Set 的内容直接添加到另一个 Set 中。合并、相交、合并等操作...是相当基本的设置操作,但不是内置的。幸运的是,您可以相当轻松地自己构建所有这些。

[2021年添加] - 现在有一项提案建议为这些类型的操作添加新的Set/ Map方法,但实施的时间尚不清楚。它们似乎处于规范过程的第 2 阶段。

要实现合并操作(将一个 Set 的内容合并到另一个 Set 中,或将一个 Map 的内容合并到另一个集合中),可以使用一行来执行此操作:.forEach()

var s = new Set([1,2,3]);
var t = new Set([4,5,6]);

t.forEach(s.add, s);
console.log(s);   // 1,2,3,4,5,6

而且,对于 a ,您可以这样做:Map

var s = new Map([["key1", 1], ["key2", 2]]);
var t = new Map([["key3", 3], ["key4", 4]]);

t.forEach(function(value, key) {
    s.set(key, value);
});

或者,在 ES6 语法中:

t.forEach((value, key) => s.set(key, value));

[2021 年新增]

由于现在有关于新 Set 方法的官方提案,因此您可以将此 polyfill 用于在 ES6+ 版本的 ECMAScript 中可用的方法。请注意,根据规范,这将返回一个新的 Set,该集合是其他两个集合的并集。它不会将一个集合的内容合并到另一个集合中,这将实现建议中指定的类型检查。.union()

if (!Set.prototype.union) {
    Set.prototype.union = function(iterable) {
        if (typeof this !== "object") {
            throw new TypeError("Must be of object type");
        }
        const Species = this.constructor[Symbol.species];
        const newSet = new Species(this);
        if (typeof newSet.add !== "function") {
            throw new TypeError("add method on new set species is not callable");
        }
        for (item of iterable) {
            newSet.add(item);
        }
        return newSet;
    }
}

或者,这里有一个更完整的版本,它模拟了ECMAScript过程,以便更完整地获取物种构造函数,并且已经适应在可能甚至没有设置的旧版本的Javascript上运行:SymbolSymbol.species

if (!Set.prototype.union) {
    Set.prototype.union = function(iterable) {
        if (typeof this !== "object") {
            throw new TypeError("Must be of object type");
        }
        const Species = getSpeciesConstructor(this, Set);
        const newSet = new Species(this);
        if (typeof newSet.add !== "function") {
            throw new TypeError("add method on new set species is not callable");
        }
        for (item of iterable) {
            newSet.add(item);
        }
        return newSet;
    }
}

function isConstructor(C) {
    return typeof C === "function" && typeof C.prototype === "object";
}

function getSpeciesConstructor(obj, defaultConstructor) {
    const C = obj.constructor;
    if (!C) return defaultConstructor;
    if (typeof C !== "function") {
        throw new TypeError("constructor is not a function");
    }

    // use try/catch here to handle backward compatibility when Symbol does not exist
    let S;
    try {
        S = C[Symbol.species];
        if (!S) {
            // no S, so use C
            S = C;
        }
    } catch (e) {
        // No Symbol so use C
        S = C;
    }
    if (!isConstructor(S)) {
        throw new TypeError("constructor function is not a constructor");
    }
    return S;
}

仅供参考,如果您想要包含方法的内置对象的简单子类,则可以使用以下方法:Set.merge()

// subclass of Set that adds new methods
// Except where otherwise noted, arguments to methods
//   can be a Set, anything derived from it or an Array
// Any method that returns a new Set returns whatever class the this object is
//   allowing SetEx to be subclassed and these methods will return that subclass
//   For this to work properly, subclasses must not change behavior of SetEx methods
//
// Note that if the contructor for SetEx is passed one or more iterables, 
// it will iterate them and add the individual elements of those iterables to the Set
// If you want a Set itself added to the Set, then use the .add() method
// which remains unchanged from the original Set object.  This way you have
// a choice about how you want to add things and can do it either way.

class SetEx extends Set {
    // create a new SetEx populated with the contents of one or more iterables
    constructor(...iterables) {
        super();
        this.merge(...iterables);
    }
    
    // merge the items from one or more iterables into this set
    merge(...iterables) {
        for (let iterable of iterables) {
            for (let item of iterable) {
                this.add(item);
            }
        }
        return this;        
    }
    
    // return new SetEx object that is union of all sets passed in with the current set
    union(...sets) {
        let newSet = new this.constructor(...sets);
        newSet.merge(this);
        return newSet;
    }
    
    // return a new SetEx that contains the items that are in both sets
    intersect(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }
    
    // return a new SetEx that contains the items that are in this set, but not in target
    // target must be a Set (or something that supports .has(item) such as a Map)
    diff(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (!target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }
    
    // target can be either a Set or an Array
    // return boolean which indicates if target set contains exactly same elements as this
    // target elements are iterated and checked for this.has(item)
    sameItems(target) {
        let tsize;
        if ("size" in target) {
            tsize = target.size;
        } else if ("length" in target) {
            tsize = target.length;
        } else {
            throw new TypeError("target must be an iterable like a Set with .size or .length");
        }
        if (tsize !== this.size) {
            return false;
        }
        for (let item of target) {
            if (!this.has(item)) {
                return false;
            }
        }
        return true;
    }
}

module.exports = SetEx;

这意味着在它自己的文件setex中.js然后您可以进入node.js并代替内置的Set使用。require()