2016-11-28 27 views
16

在jQuery中,我们有一个功能,每一个这样的什么是JavaScript中jQuery的each()函数的替代品?

$('button').each(function(i) { 
    $('button').eq(i).css('background', 'red'); 
}); 

我们如何能够用普通的JavaScript将这段代码?

+0

那么'Array.prototype.forEach()',但它本身并不能代替*那*代码。 – Pointy

+0

只需使用'for ... of'循环。 – Bergi

回答

24

querySelectorAll()

浏览器的DOM的选择有多种选择方式,从DOM元素,但也许是最灵活和方便的是querySelectorAll。它允许您使用CSS样式选择器来获取给定根目录中的所有匹配元素。

在你的情况下,它应该是这样的:

document.querySelectorAll("button"); 

缩短querySelectorAll()

很美妙,那就是,这是一个有点冗长,所以它并不少见创建缩短它的包装功能。这就是我们在这里要做的,名字为Q

function Q(root, selector) { 
    if (typeof root === "string") { 
    selector = root 
    root = document 
    } 
    return root.querySelectorAll(selector) 
} 

第一个参数是您从中进行选择的上下文,第二个参数是选择器。如果你只传递一个字符串,它将使用document作为上下文。

所以,现在你的DOM的选择会是这样,我们将在以后使用:

Q("button"); 

借款Array.prototype.forEach

一个很常见的方式做一个功能的循环结构是借用Array.prototypeforEach方法,并使用函数的在元素集合上调用它方法是这样的:

Array.prototype.forEach.call(Q("buttons"), function(el) { 
    el.style.background = "red"; 
}); 

或者在最现代的浏览器,我们可以用箭头的功能,缩短了一点:

Array.prototype.forEach.call(Q("buttons"), el => el.style.background = "red"); 

绑定和缓存借用.forEach()

.forEach()借用可以缩短d如果在应用程序的早期阶段,使用函数原型的bind()方法将.forEach()方法绑定到的值.call()

const each = Function.call.bind(Array.prototype.forEach); 

这样你就可以把它称为接收元素集合作为第一个参数的函数。

each(Q("button"), function(el) { 
    el.style.background = "red"; 
}); 

再或者在一些最新的浏览器的使用中的箭头功能:

each(Q("button"), el => el.style.background = "red"); 

使用Array.from()

Array.from方法还介绍可以轻松地转换阵列类似的对象到实际的数组中。这可让您直接使用.forEach(),并且可以使用简单的polyfill (请参阅文档链接)将其修补到传统浏览器中。

Array.from(Q("button")).forEach(function(el) { 
    el.style.background = "red"; 
}); 

如果直接把Array.from呼叫我们Q功能上面,你就可以直接调用.forEach()

Q("button").forEach(function(el) { 
    el.style.background = "red"; 
}); 

使用for-of循环

在最新的浏览器,你可以使用一个for-of loop代替,使得一切都非常短,干净:

for (const el of Q("button")) { 
    el.style.background = "red"; 
} 

这样没有必要转换为Array或使用.forEach


Transpiling现代代码

对于上面的例子中需要最现代的浏览器,可有transpilers(例如Babel),将翻译的最新标准成代码,将工作中旧版浏览器。


创建自定义each()

作为一个侧面说明,如果你想this来指代当前元素,或任何其他特定的行为,这是一个基本each实现,收到回收和回调。

function each(a, callback) { 
    for (var i = 0; i < a.length; i++) { 
    callback.call(a[i], a[i], i, a); 
    } 
} 

虽然以这种方式使用this通常不需要,因为你已经拥有的元素作为参数。

+0

不错。但在jQuery的'$(...)。each()'中,'this'将指向元素。 – haim770

+0

@ haim770:的确如此,尽管我认为OP只是想知道如何在JS中做这样的循环,而不一定完全按照它在jQuery中的表现。 – 2016-11-28 21:17:05

+1

@squint你为什么使这是一个CW? –

3
var buttons = document.querySelectorAll("button"); 
for(var x in buttons){ 
    var e = buttons[x]; 
    e.innerHTML="stuff"; 
} 

as squint指出,它应该是buttons [x]和var x。 对不起。

+0

哎呀忘了关于e =按钮[x] – MyNameIsUser9123

5

您可以使用函数getElementsByTagName()查询DOM以查找某个标记的元素并返回元素集合。您可以在document上调用此函数,或者您可以更具体一些,并使用document.getElementById()选择一个元素,然后在该元素内查找标记。

无论哪种方式,一旦你有一个元素的集合,你可以循环集合并相应地应用样式。

//query the document for all <button> elements 
var buttons = document.getElementsByTagName('button'); 

/* -- OR -- */ 

//query the document for all buttons inside of a specific element 
var container = document.getElementById('container'); 
var buttons = container.getElementsByTagName('button'); 

//loop over the collection of buttons and set each background to 'red' 
for(var i=0; i<buttons.length; i++) { 
    buttons[i].style.background = "red"; 
} 

编辑:我意识到这不是jQuery的每个函数的工作原理。 OP没有说明他想特别地看到,只是一种用JS完成$.each()功能的方法(因为有很多可能性)。这个例子只是一个使用非常基本概念的简单方法。

3

受更多浏览器支持,因为它不使用forEach

如果使用getElementsByTagName,请将函数添加到HTMLCollection

HTMLCollection.prototype.each = function(callback){ 
    for(var i=0; i<this.length; i++) callback(this[i]); 
}; 

document.getElementsByTagName('div').each(function(div){ 
    div.innerHTML = "poo"; 
}); 

如果使用querySelectorAll您可以将相同的功能NodeList

NodeList.prototype.each = function(callback){ 
    for(var i=0; i<this.length; i++) callback(this[i]); 
}; 

document.querySelectorAll('div').each(function(div){ 
    div.innerHTML = "podo"; 
}); 

为安抚chanters(见注释),我会规定,如果这是你写一个库,或者如果将它与可能覆盖它的库一起使用,显然你会想考虑其他方法。

小提琴:https://jsfiddle.net/er5amk8j/

+1

[不要修改你不拥有的对象。](http://stackoverflow.com/q/6223449/3853934) –

+0

@Gothdo不要做一揽子声明,只适用于某些情况下,否则根本没有意义。 –

+0

如果您认为这不适用于您的情况,请解释。 –

2

但你也在你的榜样可疑的方式使用$.each()。使用this访问元素更容易,更快速。

$('button').each(function(i) { 
    $(this).css('background', 'red'); 
}); 

最简单的替换就是使用简单的函数闭包,但它并不漂亮。

var $buttons = $('button'); 

for(var i = 0; i < $buttons.length; i++){ 
    (function(i){ 
    $buttons.eq(i).css('background', 'red'); 
    })(i); 
} 

,或者设置this使用.call()调用功能。

var $buttons = $('button'); 

for(var i = 0; i < $buttons.length; i++){ 
    (function(i){ 
    $(this).css('background', 'red');  
    }).call($buttons[i], i); 
} 
+0

在第二个例子中实际上并不需要IIFE,因为在循环中立即使用'i',而不是稍后在回调中使用。尽管你对OP的技术是正确的。在循环中反复调用'$('按钮')'会很慢。 – 2016-11-29 13:22:27

+0

@squint你是对的。但我已经扩展了“Michael Hamilton”的答案,目的是表明虽然结果相同,但它不是取代'.each()'的正确方法。 – Bizniztime