【问题标题】:Why can't I invoke Array.prototype.map with Set object [duplicate]为什么我不能用 Set 对象调用 Array.prototype.map [重复]
【发布时间】:2016-05-11 21:11:16
【问题描述】:

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

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

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

Set 是可迭代的对象,那为什么我们不能使用map 函数来迭代set呢?

我尝试通过这种方式将chars set 和chars.values() SetIterator 传递给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 函数?如果没有 - 为什么?

【问题讨论】:

  • 您是否尝试过使用Set.entries?实际上,再想一想,我认为这行不通……
  • stackoverflow.com/a/35374005/5812121。也可以选择:let result = [...chars].map(c => `_${c}`);

标签: javascript arrays set ecmascript-6


【解决方案1】:

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}`);

用于将可迭代对象转换为数组的漂亮而简短的映射。

【讨论】:

  • 无法通过 index 访问设置条目,但可以保证顺序......我无法克服这个:)
  • MDN 说Set 是可迭代的。并且Array.prototype.maps 规范说 map 获取可迭代对象:MDN: map。那么为什么我不能将 set 作为参数传递给map
  • @YuriyYakym 我认为这是因为 Set 实例不能像数组一样使用数字索引进行索引,而这正是 .map().filter().forEach() 等数组函数所依赖的.
  • 查看同一页面上的Polyfill,这是规范的逐步实现,您会看到它需要length 属性,并且值是可按索引寻址。
  • @YuriyYakym 该链接适用于Map,而不是Array.prototype.map
【解决方案2】:

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

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

【讨论】:

  • 展开然后映射会无缘无故创建一个临时数组。你可以使用Array.from同时做一个数组和映射。
  • @loganfsmyth :Array.from() 方法从类数组或可迭代对象创建一个新的 Array 实例。 (这是 MDN 上Array.from() 描述的第一行)developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 如果您想在函数式编程等之后使用数组方法或将唯一元素作为参数数组传递给函数,这非常实用。没有必要为此创建一个浪费的数组。
  • 我的意思是[...chars].map(fn)Array.from(chars).map(fn) 都创建一个数组,然后调用.map 来返回第二个数组,而您可以使用Array.from(chars, fn) 来创建避免创建第一个临时数组。
【解决方案3】:

因为即使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);
}());

【讨论】:

  • 映射Array.from 的结果将无缘无故地创建一个临时数组。您将回调作为第二个参数传递。
猜你喜欢
  • 2021-06-18
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
相关资源
最近更新 更多