尝试使用vanilla JS创建一个每个方法,就像在jQuery中一样

Trying to make an each method, like in jQuery, with vanilla JS

本文关键字:jQuery 一样 方法 创建 JS 一个 vanilla      更新时间:2023-09-26
Element.prototype.each = function(fn) {
  for(var i = 0; i < this.length; i++) {
    fn(i);
  } 
};
var li = document.getElementsByTagName('li');
li.each(function(i) {
  this.style.borderBottom = '1px solid red';
});

我正在尝试像jQuery一样制作每个方法。我在 for 循环和回调中尝试了很多东西,但我遇到了错误。我敢肯定这与"这个"上下文有关。

您可以使用调用来设置上下文

编辑Element不是正确的类,它应该是NodeListHTMLCollection

NodeList.prototype.each = HTMLCollection.prototype.each = function(fn) {
  for(var i = 0; i < this.length; i++) {
    fn.call(this, i);
  } 
};

当您使用Function.prototype.call时,它允许您将上下文(AKA this(绑定到函数

AFAIK 有 3 种方法可以做到这一点:

  • 呼叫(如上所述(
  • apply(它的工作原理类似于调用,除了它只需要两个参数,第二个是一个数组(
  • 绑定(用于咖喱(

另请注意,从 DOM 级别 4(ES6 和声(开始,有一个名为 Elements 的新类,它扩展了Array,旨在替换 NodeList/HTMLCollection ,因此您无需在 ES6 中实际扩展它即可添加 each 方法并使用Array.prototype.forEach(尽管您将无法在回调中使用this

document.getElementsByTagName('li')返回HTML Collection对象,而不是Element

复制 jQuery each非常容易(本机forEach$.each之间的唯一区别是参数的顺序 - $.each使用(i,el)元组,[].forEach使用元组(el,i)(。在现代浏览器(IE8 除外(中,您只需使用:

document.getElementsByTagName('li').constructor.prototype.each = function(fn,thisArg) {
    [].forEach.call(this, function(el,i,array) {
        fn.call(thisArg, i,el,array);
    });
};

我不建议扩展本机原型,您应该改用[].forEach.call(yourNodeList, func)。可以执行yourNodeList = [].slice.call(yourNodeList);将 DOM 集合转换为纯数组。

我最近有理由以类似的方式解决一个特定的问题,并有兴趣看看其他人是如何解决它的。 牢记有关扩展本机原型的警告,我只是记录我的解决方案,仅在浏览器环境中实现,供后代使用。

/* For Arrays, enumerable Objects,
   DOMTokenLists and HTMLCollections etc */
Object.prototype.each = function(fn) {
    (Array.isArray(this) ? this : (this.constructor.name === 'Object' ? Object.keys(this) : [].slice.call(this))).forEach(fn);
};

:)