为什么可以't我用Set对象调用Array.prototype.map

Why can't I invoke Array.prototype.map with Set object

本文关键字:对象 Set 调用 Array map prototype 我用 为什么      更新时间:2023-09-26

我想使用ES6的Set从某个字符串中获取唯一字符。因此,让我们假设我们有字符串var str = 'abcdeaabc';,并从这个字符串创建一组字符:

var str = 'abcdeaadbc';
var chars = new Set(str);

现在我们有了一组独特的字符:abcd。我很惊讶char集合有forEach方法而没有map方法。

Set是可迭代的对象,为什么不能使用map函数对Set进行迭代呢?

我试图通过以下方式将chars集和chars.values()集Iterator传递给Array.prototype.map

Array.prototype.map.call(chars, function(element) {...});
Array.prototype.map.call(chars.values(), function(element) {...});

但每一次尝试都失败了。

例如,假设我们想从字符串中获得唯一的符号,并返回一个带有前下划线的符号数组。例如:['_a', '_b', '_c', '_d']

以下是我的两个解决方案:

// First:
var result = Array.from(chars).map(function(c) {
    return '_' + c;
});
// Second:
var result = [];
chars.forEach(function(c) {
    this.push('_' + c);
}, result);

但是有没有一种方法可以用Set上下文调用Array.prototype的map函数?如果没有,为什么?

Array.prototype.map适用于具有整数索引和length属性的类数组类型。SetMap是一般的可迭代类型,但它们不是类似数组的,因此Array.prototype方法将无法对它们起作用。例如

var s = new Set([1, 2, 3]);
s.length === undefined;
s[0] === undefined

主要的方法是Array.from有点像您的解决方案,但需要注意的是,Array.frommapFn作为第二个参数,因此您可以执行

let results = Array.from(chars, c => `_${c}`);

以获得一个漂亮而简短的映射,将可迭代映射转换为数组。

如果你绝望了,你可以这样做

var str = 'abcdeaadbc';
var chars = new Set(str);
document.write("<pre>" + JSON.stringify([...chars].map(c => c+"up")) + "</pre>")

因为即使map足够通用,可以用于任意类似数组的对象,但并非所有可迭代对象都是类似数组的。

map只获取length属性,然后将属性从0迭代到length-1。这不能用于集合,因为它们有size而不是length,并且它们不提供对其元素的随机访问。

如果您真的想使用map,则需要将集合转换为数组,然后将结果转换回集合。

var newSet = new Set(Array.from(set).map(myFunc));

但这样做没有意义,最好只使用设置操作:

var newSet = new Set();
for(let val of set) newSet.add(myFunc(val));

或者可能是一个自调用的生成器函数:

var newSet = new Set(function*() {
  for(let val of set) yield myFunc(val);
}());