Is it possible to use array iteration methods on E

2019-02-23 18:48发布

问题:

I am using ES6 Set instances and I need to apply some transformations on them. These are transformations of the kind that would be simple if they were arrays. Here is an example:

let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = s.filter(val => val > 1); // TypeError, filter not defined
let n = Array.prototype.filter.call(s, val => val > 1); // []

I was hoping that the result would either be a new Set or an array. I similarly want to use other array comprehension methods like filter, map, reduce, etc. And I would also like to have similar behaviour on ES6 Map instances as well.

Is this possible, or do I need to be using vanilla JS arrays?

回答1:

you can get the values of s in an array using

Array.from(s.values())

Array.from documentation states that it creates a new Array instance from an array-like or iterable object.

Set.values returns a new Iterator object that contains the values for each element in the Set object in insertion order.

So your code becomes

let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = Array.from(s.values()).filter(val => val > 1)


回答2:

You can't use Array methods directly on a Set or Map object. Array methods expect .length and [n] indexing which is not how Set or Map work.

You can either convert your Set to an array using Array.from(s) or you can create your own methods to operate directly on the Set or Map. If you're going to be doing this a lot and the desired end result is a Set or Map, then it's probably better to not convert to an Array, modify, then convert back. Plus, converting a Map to an array is not quite so simple since you have both a key and value (might have to be an array of objects).

For example, you could create your own .filter() method for a Set object like this:

Set.prototype.filter = function(fn) {
    let result = new Set();
    for (let val of this) {
       if (fn(val, this) === true) {
           result.add(val);
       }
    }
    return result;
}

let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = s.filter(val => val > 1); 


// log the output

// log output
document.write("Set {" + Array.from(n).join(", ") +"}");

Similar methods could be created for other Array methods.