什么是JavaScript中jQuery的each()函数的替代品?

时间:2016-11-28 21:07:42

标签: javascript jquery

在jQuery中我们有一个像这样的函数

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

我们如何用纯JavaScript替换此代码?

5 个答案:

答案 0 :(得分:26)

使用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.prototype的{​​{3}}方法,并使用函数的forEach方法在元素集合上调用它,如下所示:

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()借用,使用函数原型的.call()方法将.forEach()方法绑定到this .call()的值const each = Function.call.bind(Array.prototype.forEach); 1}}。

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

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

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

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

Array.from()

使用.forEach()

还引入了bind()方法,可以轻松地将类似数组的对象转换为实际数组。这样您就可以直接使用Array.from(Q("button")).forEach(function(el) { el.style.background = "red"; }); ,并可以使用简单的polyfill 修补旧版浏览器(请参阅文档链接)

Array.from

如果您将Q电话直接放在我们.forEach()的上述功能中,您就可以直接拨打Q("button").forEach(function(el) { el.style.background = "red"; });

for-of

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

在最新的浏览器中,您可以使用Array.from代替,使所有内容都非常简洁:

Array

这样就无需转换为.forEach或使用each()

展示现代代码

对于需要最现代浏览器的上述示例,可以使用转换器(例如for-of loop)将最新标准转换为可在旧版浏览器中使用的代码。

制作自定义this

作为旁注,如果您希望each引用当前元素,或者有任何其他特定行为,这里是一个接收集合和回调的基本function each(a, callback) { for (var i = 0; i < a.length; i++) { callback.call(a[i], a[i], i, a); } } 实现。< / p>

this

虽然通常不需要使用 2016-11-28 20:48:29.277 SquaresApp[12766:589296] -[SquaresApp.RemoveAdsView handleTap]: unrecognized selector sent to instance 0x7f84ffc0b1e0 2016-11-28 20:48:29.301 SquaresApp[12766:589296] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SquaresApp.RemoveAdsView handleTap]: unrecognized selector sent to instance 0x7f84ffc0b1e0' *** First throw call stack: ( 0 CoreFoundation 0x00000001107c434b __exceptionPreprocess + 171 1 libobjc.A.dylib 0x000000010fbe921e objc_exception_throw + 48 2 CoreFoundation 0x0000000110833f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132 3 CoreFoundation 0x0000000110749c15 ___forwarding___ + 1013 4 CoreFoundation 0x0000000110749798 _CF_forwarding_prep_0 + 120 5 UIKit 0x0000000111640e41 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 57 6 UIKit 0x0000000111648be0 _UIGestureRecognizerSendTargetActions + 109 7 UIKit 0x00000001116466af _UIGestureRecognizerSendActions + 227 8 UIKit 0x000000011164593b -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 891 9 UIKit 0x0000000111631a0e _UIGestureEnvironmentUpdate + 1395 10 UIKit 0x0000000111631453 -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 521 11 UIKit 0x0000000111630636 -[UIGestureEnvironment _updateGesturesForEvent:window:] + 286 12 UIKit 0x000000011116f3b9 -[UIWindow sendEvent:] + 3989 13 UIKit 0x000000011111c63f -[UIApplication sendEvent:] + 371 14 UIKit 0x000000011190e71d __dispatchPreprocessedEventFromEventQueue + 3248 15 UIKit 0x00000001119073c7 __handleEventQueue + 4879 16 CoreFoundation 0x0000000110769311 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 17 CoreFoundation 0x000000011074e59c __CFRunLoopDoSources0 + 556 18 CoreFoundation 0x000000011074da86 __CFRunLoopRun + 918 19 CoreFoundation 0x000000011074d494 CFRunLoopRunSpecific + 420 20 GraphicsServices 0x0000000114a1ea6f GSEventRunModal + 161 21 UIKit 0x00000001110fe964 UIApplicationMain + 159 22 SquaresApp 0x000000010c0f80ef main + 111 23 libdyld.dylib 0x000000011324068d start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException ,因为您已经将元素作为参数。

答案 1 :(得分: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";
}

编辑:我意识到这不是JS背后jQuery的每个功能的工作方式。 OP并没有声明他想要明确地看到这一点,只是通过JS实现$.each()功能的一种方式(因为有很多可能性)。这个例子只是一个使用非常基本概念的简单方法。

答案 2 :(得分:4)

var buttons = document.querySelectorAll("button");
for(var x in buttons){
  var e = buttons[x];
  e.innerHTML="stuff";
}
斜视指出,它应该是按钮[x]和var x。 抱歉。

答案 3 :(得分: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";
});

为了安抚这些话题(请参阅注释),我将指定如果这是针对您正在编写的库,或者如果它将与可能会覆盖它的库一起使用,显然您会想要考虑其他方法。

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

答案 4 :(得分: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);
}