New collections methods

1 Formal informations

2 Set.prototype methods

2.1 Set.prototype.filter( callbackfn [ , thisArg ] )

When the filter method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let Ctr be ? SpeciesConstructor(set, %Set%)
  5. Let newSet be ? Construct(Ctr)
  6. Let adder be ? Get(newSet, "add")
  7. If IsCallable(adder) is false, throw a TypeError exception.
  8. Let entries be the List that is set.[[SetData]]
  9. For each e that is an element of entries, in original insertion order, do:
    1. If e is not empty, then
      1. Let selected be ToBoolean(? Call(callbackfn, T, « e, e, set »))
      2. If selected is true, then:
        1. Call(adder, set, « e »)
  10. Return newSet.

2.2 Set.prototype.map( callbackfn [ , thisArg ] )

When the map method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let Ctr be ? SpeciesConstructor(set, %Set%)
  5. Let newSet be ? Construct(Ctr)
  6. Let adder be ? Get(newSet, "add")
  7. If IsCallable(adder) is false, throw a TypeError exception.
  8. Let entries be the List that is set.[[SetData]]
  9. For each e that is an element of entries, in original insertion order, do:
    1. If e is not empty, then
      1. Let mappedValue be Call(callbackfn, T, « e, e, set »)
      2. Call(adder, set, « mappedValue »)
  10. Return newSet.

2.3 Set.prototype.find( callbackfn [ , thisArg ] )

When the find method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is set.[[SetData]]
  5. For each ele that is an element of entries, in original insertion order, do:
    1. If ele is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « ele, ele, set »))
      2. If testResult is true, then return ele
  6. Return undefined.

2.4 Set.prototype.some( callbackfn [ , thisArg ] )

When the some method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is set.[[SetData]]
  5. For each e that is an element of entries, in original insertion order, do:
    1. If e is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e, e, set »))
      2. If testResult is true, then return true
  6. Return false.

2.5 Set.prototype.every( callbackfn [ , thisArg ] )

When the every method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is set.[[SetData]]
  5. For each e that is an element of entries, in original insertion order, do:
    1. If e is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e, e, set »))
      2. If testResult is false, then return false
  6. Return true.

2.6 Set.prototype.reduce( callbackfn [ , initialValue ] )

When the reduce method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. Let entries be the List that is set.[[SetData]].
  4. Let accumulator be undefined
  5. Let first be true.
  6. If initialValue is present, then
    1. Set accumulator to initialValue
  7. For each e that is an element of entries, in original insertion order, do:
    1. If e is not empty, then
      1. If first be true and initialValue is not present:
        1. Set accumulator to e
      2. Else,
        1. Set accumulator to ? Call(callbackfn, undefined, « accumulator, e, e, map »)
      3. Set first to false
  8. If first is true and initialValue is not present, throw TypeError exception.
  9. Return accumulator.

2.7 Set.prototype.join( [ separator ] )

When the join method is called, the following steps are taken:

  1. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  2. If separator is undefined, let sep be the single-element String ",".
  3. Else, let sep be ? ToString(separator).
  4. Let R be the empty String.
  5. Let entries be the List that is set.[[SetData]]
  6. Let k be false.
  7. For each element that is an element of entries, in original insertion order, do:
    1. If element is not empty, then
      1. If k is true, let R be the string-concatenation of R and sep.
      2. Set k to true.
      3. Let next be ? ToString(element).
      4. Set R to the string-concatenation of R and next.
      5. Increase k by 1.
  8. Return R.

2.8 Set.prototype.addAll(...items)

When the addAll method is called, the following steps are taken:

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
    2. If set does not have a [[SetData]] internal slot, throw a TypeError exception.
  4. Let elements be CreateArrayFromList(items).
  5. Let adder be ? Get(set, "add")
  6. Return ? AddEntriesFromIterable(set, elements, adder).

The length property of the addAll method is 0.

2.9 Set.prototype.deleteAll(...items)

When the deleteAll method is called, the following steps are taken:

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let set be the this value.
    1. If Type(set) is not Object, throw a TypeError exception.
  4. Let k be 0.
  5. Let remover be ? Get(set, "delete")
  6. If IsCallable(remover) is false, throw a TypeError exception.
  7. Let allDeleted be true.
  8. Repeat while k < len
    1. Let value be items[k].
    2. Let wasDeleted be Call(remover, set, value)
    3. Set allDeleted to be allDeleted && wasDeleted
    4. Increase k by 1.
  9. Return ToBoolean(allDeleted);

3 Map.prototype methods

3.1 Map.prototype.mapValues( callbackfn, [ thisArg ] )

Editor's Note
This code serves as placeholder until formal spec is written for this method.
function mapValues(callbackFn, thisArg) {
    assert(isObject(this), 'this is not an object');
    assert(isCallable(callbackFn), 'callback is not a function');
    const Ctor = SpeciesConstructor(this, Map);
    const retObj = new Ctor();
    const _set = retObj.set;
    for(const [key, value] of this) {
        const newValue = Reflect.apply(callbackFn, thisArg, [value, key, this])
        Reflect.apply(_set, retObj, [key, newValue]);
    }
    return retObj;
}

3.2 Map.prototype.mapKeys( callbackfn, [ thisArg ] )

Editor's Note
This code serves as placeholder until formal spec is written for this method.
function mapKeys(callbackFn, thisArg) {
    assert(isObject(this), 'this is not an object');
    assert(isCallable(callbackFn), 'callback is not a function');
    const Ctor = SpeciesConstructor(this, Map);
    const retObj = new Ctor();
    const _set = retObj.set;
    for(const [key, value] of this) {
        const newKey = Reflect.apply(callbackFn, thisArg, [value, key, this])
        Reflect.apply(_set, retObj, [newKey, value]);
    }
    return retObj;
}

3.3 Map.prototype.filter( callbackfn, [ thisArg ] )

Editor's Note
This code serves as placeholder until formal spec is written for this method.
  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let Ctr be ? SpeciesConstructor(map, %Map%)
  5. Let newMap be ? Construct(Ctr)
  6. Let adder be ? Get(newSet, "set")
    1. If IsCallable(adder) is false, throw a TypeError.
  7. Let entries be the List that is map.[[MapData]]
  8. Let newMapData be new empty List.
  9. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty, then
      1. Let key be p.[[Key]]
      2. Let value be p.[[Value]]
      3. Let selected be ToBoolean(? Call(callbackfn, T, « value, key, map »))
      4. If selected is true, then
        1. Let pair be CreateArrayFromListvalue, key »)
        2. Append pair as last element to newMapData.
  10. Return ? AddEntriesFromIterable(map, CreateArrayFromList(newMapData), adder).

3.4 Map.prototype.find( callbackfn [ , thisArg ] )

When the find method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is map.[[MapData]].
  5. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e.[[Value]], e.[[Key]], map »)).
      2. If testResult is true, then return e.[[Value]].
  6. Return undefined.

3.5 Map.prototype.findKey( callbackfn [ , thisArg ] )

When the findKey method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is map.[[MapData]].
  5. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e.[[Value]], e.[[Key]], map »)).
      2. If testResult is true, then return e.[[Key]].
  6. Return undefined.

3.6 Map.prototype.keyOf( searchElement )

When the keyOf method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. Let entries be the List that is map.[[MapData]].
  3. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. Let same be the result of performing Strict Equality Comparison searchElement === e.[[Value]].
      2. If same is true, then return e.[[Key]].
  4. Return undefined.

3.7 Map.prototype.some( callbackfn [ , thisArg ] )

When the some method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is map.[[MapData]].
  5. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e.[[Value]], e.[[Key]], map »))
      2. If testResult is true, then return true
  6. Return false.

3.8 Map.prototype.every( callbackfn [ , thisArg ] )

When the every method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. If thisArg was supplied, let T be thisArg; else let T be undefined.
  4. Let entries be the List that is map.[[MapData]].
  5. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. Let testResult be ToBoolean(? Call(callbackfn, T, « e.[[Value]], e.[[Key]], map »))
      2. If testResult is false, then return false
  6. Return true.

3.9 Map.prototype.includes( searchElement )

When the includes method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. Let entries be the List that is map.[[MapData]].
  3. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. If SameValueZero(searchElement, e.[[Value]]) is true, return true.
  4. Return false.

3.10 Map.prototype.reduce( callbackfn [ , initialValue ] )

When the reduce method is called, the following steps are taken:

  1. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. Let entries be the List that is map.[[MapData]].
  4. Let accumulator be undefined
  5. Let first be true.
  6. If initialValue is present, then
    1. Set accumulator to initialValue
  7. For each Record { [[Key]], [[Value]] } e that is an element of entries, in original key insertion order, do:
    1. If e.[[Key]] is not empty, then
      1. If first be true and initialValue is not present:
        1. Set accumulator to e.[[Value]]
      2. Else,
        1. Set accumulator to ? Call(callbackfn, undefined, « accumulator, e.[[Value]], e.[[Key]], map »)
      3. Set first to false
  8. If first is true and initialValue is not present, throw TypeError exception.
  9. Return accumulator.

3.11 Map.prototype.merge(... iterables )

Editor's Note
This code serves as placeholder until formal spec is written for this method.
function merge(...iterables) {
    assert(isObject(this), 'this is not an object');
    assert(this instanceof Map, 'this is not a Map instance');
    for(const iterable of iterables) {
        for(const [key, value] of iterable) {
            this.set(key, value);
        }
    }

    return this;
}

3.12 Map.prototype.deleteAll(...items)

When the deleteAll method is called, the following steps are taken:

The length property of the deleteAll method is 0.

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let map be the this value.
    1. If Type(map) is not Object, throw a TypeError exception.
    2. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  4. Let k be 0.
  5. Let remover be ? Get(map, "delete")
  6. If IsCallable(remover) is false, throw a TypeError exception.
  7. Repeat while k < len
    1. Let value be items[k].
    2. Call(remover, map, value)
    3. Increase k by 1.
  8. Return map.

3.13 Map.prototype.update(key, callback [, thunk])

Editor's Note
This code serves as placeholder until formal spec is written for this method.
function update(key, cb, thunk) {
    assert(isObject(this), 'this is not an object');
    assert(isCallable(callbackFn), 'callback is not a function');
    asset(isMap(this), 'this is not a Map instance');
    const isPresentInMap = this.has(key);
    if (isPresentInMap === false && arguments.length < 3) {
        throw new Error('Invalid!');
    }
    const value = isPresentInMap ? this.get(key) : thunk(key, this);
    const newValue = cb(value, key, this);
    this.set(key, newValue);
    return this;
}

4 Map static methods

4.1 Map.keyBy( iterable, callbackfn)

When the keyBy method is called, the following steps are taken:

  1. Let C be the this value.
  2. If IsConstructor(C) is true
    1. Let map be ? Construct(C)
  3. Else,
    1. Throw a TypeError.
  4. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  5. If IsCallable(callbackfn) is false, throw a TypeError exception.
  6. Let set be ? Get(map, "set")
  7. Let iteratorRecord be ? GetIterator(iterable).
  8. Repeat,
    1. Let next be ? IteratorStep(iteratorRecord).
    2. If next is false, return map.
    3. Let item be ? IteratorValue(next).
    4. Let key be Call(callbackfn, null, « item »)
    5. Let status be Call(set, map, « key.[[Value]], value.[[Value]] »).
    6. If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).

4.2 Map.groupBy( iterable, callbackfn)

When the groupBy method is called, the following steps are taken:

  1. Let C be the this value.
  2. If IsCallable(callbackfn) is false, throw a TypeError exception.
  3. Let iteratorRecord be ? GetIterator(iterable).
  4. Let internalList be new empty List.
  5. Let next be guard value.
  6. If IsConstructor(C) is true
    1. Let map be ? Construct(C)
  7. Else,
    1. Throw a TypeError.
  8. If map does not have a [[MapData]] internal slot, throw a TypeError exception.
  9. Repeat while next is not false,
    1. Set next be ? IteratorStep(iteratorRecord).
    2. If next is not false,
      1. Let item be ? IteratorValue(next);
      2. Let key be Call(callbackfn, null, « item »)
      3. If key is an abrupt completion, return ? IteratorClose(iteratorRecord, key).
      4. Let entryWasFound be false
      5. For each Record { [[Key, [[Value]] } p that is an element of internalList, do
        1. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], key) is true, then
          1. Let grouped be p.[[Value]]
          2. Append item as last element of grouped.
          3. Let entryWasFound be true.
      6. If entryWasFound is false
        1. Let groupedList be « item ».
        2. Let record be the Record { [[Key]]: key, [[Value]]: groupedList }
        3. Append record as last element of internalList.
  10. Let intermediateList be new empty List.
  11. For each record in internalList,
    1. Let arr be CreateArrayFromList(record.[[Value]]).
    2. Let pair be CreateArrayFromListrecord.[[Key]], arr »)
    3. Append pair as last element of intermediateList.
  12. newMapData be CreateArrayFromList(intermediateList)
  13. Let adder be ? Get(map, "set")
  14. Return ? AddEntriesFromIterable(map, newMapData, adder).

5 WeakSet.prototype.addAll(...items)

When the addAll method is called, the following steps are taken:

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let weakset be the this value.
    1. If Type(weakset) is not Object, throw a TypeError exception.
  4. Let k be 0.
  5. Let adder be ? Get(weakset, "add")
  6. If IsCallable(adder) is false, throw a TypeError exception.
  7. Repeat while k < len
    1. Let kValue be items[k].
    2. Call(adder, weakset, kValue)
    3. Increase k by 1.
  8. Return weakset.

The length property of the addAll method is 0.

6 WeakSet.prototype.deleteAll(...items)

When the deleteAll method is called, the following steps are taken:

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let weakset be the this value.
    1. If Type(weakset) is not Object, throw a TypeError exception.
  4. Let k be 0.
  5. Let remover be ? Get(weakset, "delete")
  6. If IsCallable(remover) is false, throw a TypeError exception.
  7. Repeat while k < len
    1. Let value be items[k].
    2. Call(remover, weakset, value)
    3. Increase k by 1.
  8. Return weakset.

The length property of the deleteAll method is 0.

7 WeakMap.prototype.deleteAll(...items)

When the deleteAll method is called, the following steps are taken:

  1. Let len be the actual number of arguments passed to this function.
  2. Let items be the List of arguments passed to this function.
  3. Let weakmap be the this value.
    1. If Type(weakmap) is not Object, throw a TypeError exception.
  4. Let k be 0.
  5. Let remover be ? Get(weakmap, "delete")
  6. If IsCallable(remover) is false, throw a TypeError exception.
  7. Repeat while k < len
    1. Let value be items[k].
    2. Call(remover, weakmap, value)
    3. Increase k by 1.
  8. Return weakmap.

The length property of the deleteAll method is 0.

A Copyright & Software License

Copyright Notice

© 2021 Michał Wadas, Ecma International

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.