干掉 htmlCollection 到 Array 调用

DRY up htmlCollection to Array calls

我有一个函数当前正在使用 JavaScript 中的 .getElementBy... DOM 调用。

var $ = function (selector) {
  var elements = [];

  var lastSelector  = selector.substring(selector.search(/[^#.]+$/), selector.length);

  if(selector.includes('#') !== true || selector.includes('.') !== true) {
    elements.push(document.getElementsByTagName(lastSelector));
    elements = Array.prototype.slice.call(elements[0]);
  }

return elements;
};

函数中还有许多其他 if 语句使用代码:

elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);

elements.push(document.getElementsByClassName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);

理想情况下,我想干掉重复的内容:

elements = Array.prototype.slice.call(elements[0]);

但我无法在 if 语句之前定义它,因为尚未填充元素。因此,它会尝试 运行 空数组上的代码并出错。

有什么建议吗?

您可以使用所有浏览器(包括 IE8+)中可用的标准 querySelectorAll(),而不是使用选择器选择元素的自制有限函数。

至于将类似数组的对象(例如 DOM 集合)转换为真正的 ArrayArray.prototype.slice.call() 在您的代码中的用途),我使用以下函数:

var arrayFrom = function(arrayLike) {
    if (Array.from) {
        return Array.from(arrayLike);
    }

    var items;

    try {
        items = Array.prototype.slice.call(arrayLike, 0);
    }
    catch(e) {
        items = [];

        var count = arrayLike.length;

        for (var i = 0; i < count; i++) {
            items.push(arrayLike[i]);
        }
    }

    return items;
};

或其以下简化版本,如果浏览器不支持将非 Array 参数传递给 Array.prototype.slice.call()(IE8- 如果我没记错的话)无关紧要:

var arrayFrom = function(arrayLike) {
    return Array.from
         ? Array.from(arrayLike);
         : Array.prototype.slice.call(arrayLike, 0);
};

当然要考虑@marat-tanalin 的回答。在无法使用 querySelectorAll() 的情况下,以下对我有用,感谢@master565 的帮助:

开始,换行:

elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);

在函数中:

function pushByTag(selector) {
  elements.push(document.getElementsByTagName(selector));
  elements = Array.prototype.slice.call(elements[0]);
}

干货很多。然后为 if 参数设置一个变量很有帮助:

if(selector.includes('#') !== true || selector.includes('.') !== true)

变成了:

var noClassOrId = selector.includes('#') !== true || selector.includes('.') !== true;

这两个重构都允许我将我的 if 语句单行化为我认为相当可读的内容:

if (noClassOrId) pushByTag(lastSelector);