尝试使用vanilla JS制作每个方法,例如jQuery

时间:2014-12-18 10:40:00

标签: javascript

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循环和回调中尝试了很多东西,但是我遇到了错误。我确定这与这个&#39;这个&#39;上下文。

3 个答案:

答案 0 :(得分:8)

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

编辑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有三种方法可以做到这一点:

  • call(如上所述)
  • apply(除了只需要两个参数,第二个是数组之外,就像调用一样工作)
  • bind(用于currying

另请注意,自DOM level 4 (ES6 harmony)起,有一个名为Elements的新类,其扩展为Array,旨在取代NodeList / HTMLCollection,因此您不需要在ES6中实际扩展它以添加each方法并使用Array.prototype.forEach代替(尽管您在回调中无法使用this

答案 1 :(得分:3)

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

复制jQuery each非常容易(原生forEach$.each之间的唯一区别是参数顺序 - $.each使用(i,el) } tuple,[].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集合转换为普通数组。

答案 2 :(得分:0)

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

/* 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);
};

:)