简体   繁体   English

将javascript“几乎数组”转换为“数组”的最干净方法是什么?

[英]What is the cleanest way to convert javascript “almost arrays” into “arrays”?

I have been playing around with JavaScript for the past few months and found it to be really refreshing after not using it for many years. 在过去的几个月中,我一直在使用JavaScript,发现使用了很多年后,它确实令人耳目一新。

That said, one thing in particular that really bothers me is its' inconsistancies in how it describes "[]" construct. 就是说,特别令我困扰的一件事是它在描述“ []”结构方面的不一致之处。

In particular, I am used to having Arrays have a "map" function, but many things that are "[]"-enclosed do not support map, but often support a synonym, and sometimes don't at all. 特别是,我习惯于让数组具有“映射”功能,但是很多用[[]”括起来的东西不支持映射,但是通常支持同义词,有时甚至根本不支持。

Examples: 例子:

  1. document.getElementById('my-div').children document.getElementById('my-div')。children

Has no mappability at all and each time I need to map over it, I have to resort to for loops. 完全没有可映射性,每次我需要对其进行映射时,都必须求助于for循环。

  1. document.querySelectorAll('#my-div *') document.querySelectorAll('#my-div *')

Has forEach :: callback -> undefined forEach :: callback -> undefined

Unlike map, does not return an array, so chaining transformations is "strange" because in addition to mapping over the object, you also have to store the results in an array to continue. 与map不同,它不返回数组,因此链接转换是“奇怪的”,因为除了在对象上进行映射外,还必须将结果存储在数组中才能继续。

This means the following won't work. 这意味着以下操作无效。

(() => {
    document.querySelectorAll('#my-div *').forEach((divObject) => {
        console.log('found a ' + divObject.tagName + '.');
        return divObject;
    }).forEach((divObject) => {
        console.log('more transformations on ' + divObject.tagName + '.');
        return divObject;
    });
})();

but this will: 但这将:

(() => {
    var children = [];

    document.querySelectorAll('#my-div *').forEach((divObject) => {
        children.push(divObject);
    });

    children.map((divObject) => {
        console.log('found a ' + divObject.tagName + '.');
        return divObject;
    }).map((divObject) => {
        console.log('more transformations on ' + divObject.tagName + '.');
        return divObject;
    });
})();

But the copying of elements "one by one" inside a forEach is just extra work that serves no real purpose, and generally should be optimized out before publishing code like this, as it is a detriment to performance for no good reason. 但是在forEach中“一个接一个”地复制元素只是没有实际目的的额外工作,通常应该在发布这样的代码之前对其进行优化,因为这完全有损于性能。

  1. jQuery's map works correctly. jQuery的地图正常工作。 eg $('#my-div *') has a map :: callback -> array that supports map operation . 例如$('#my-div *')有一个map :: callback -> array that supports map operation So it can be chained as expected. 因此它可以按预期方式链接。

The Question : 问题

Is there a cleaner way to overcome the inconsistancy of array-like interfaces(things that appear to be "Arrays" but do not support Array.prototype.map) than having to do the first-iteration using a for loop, pushing the contents, only after that knowing that it behaves the way you think it behaves? 是否有一种比必须使用for循环进行第一次迭代,推入内容的方法更有效的方法来克服类似数组的接口(看起来像“数组”但不支持Array.prototype.map的东西)的不一致问题。仅在知道它的行为方式与您认为的行为方式相同之后?

For all exotic arrays like node lists etc if they are iterable you can safely do like 对于节点列表等所有奇异数组,如果它们是可迭代的,则可以放心地执行

var properArray = [...arrayLike] or var properArray = Array.from(arrayish) var properArray = [...arrayLike]var properArray = Array.from(arrayish)

or you can even do like 或者你甚至可以喜欢

var properarray = Array(arrayish.length),
              i = 0;
for (var key of arrayish) while i < arrayish.length properArray[i++] = arrayish(key);

If you have an object like 如果你有一个像

 var o = {prop_1:"one thing", prop_2:"another thing"}, a = []; o[Symbol.iterator] = function* (){ var oks = Object.keys(this); for (var key of oks) yield this[key] } a = [...o]; console.log(a); 

you can make it iterable and convert it into an array the same way; 您可以使其迭代,并以相同的方式将其转换为数组;

You can avoid making a copy of an array by using .apply : 您可以避免使用.apply复制数组:

var nodeList = document.getElementsByTagName("p");

Array.prototype.map.apply(nodeList, function(node) {
  // do something with node
});

(Obviously the call to .map() will itself make a new array, but that's going to happen anyway.) (显然,对.map()的调用本身会创建一个新数组,但是无论如何都会发生这种情况。)

My suggestion is: avoid chaining . 我的建议是: 避免链接

Converting to array and mapping just to be able to chain forEach is a waste. 仅仅为了能够链接forEach而转换为数组和映射是一种浪费。

Instead, just store the NodeList in a variable. 相反,只需将NodeList存储在变量中。

 var nodes = document.querySelectorAll('*'); nodes.forEach(node => console.log('found a ' + node.tagName + '.')) nodes.forEach(node => console.log('more transformations on ' + node.tagName + '.')); 

Note NodeList weren't iterable until DOM4. 注意NodeList在DOM4之前是不可迭代的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM