jQuery 使用 $(this) 作为 setInterval/setTimeOut 函数内的起点遍历 DOM?

问题描述

我一直试图了解如何(在 jQuery 中)使用 $(this) 作为 setInterval/setTimeOut 函数内的起点遍历 DOM,并且遇到了一些我发现令人困惑的行为。

在 setInterval/setTimeOut 函数中使用 $(this) 作为起点来遍历 DOM 似乎是不可能的

这是为什么?
jQuery/javaScript 人员 - 继续。

演示行为的示例代码

jQuery:

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(function(){
    // INSERT EXAMPLE TEST-CODE FROM BELOW HERE
},10000)

尝试过的测试代码

// from inside the setInterval/setTimeOut function above
// if $(this)
if($(this).length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if html-tag (body/head/html)
if($('body').length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if className
if($('.className').length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if id
if($('#id').length !== 0) {
    alert('hello');
} // alerts hello

因此它可以很好地找到文档中的特定元素,除了 $(this) 之外,您还可以从那里遍历 DOM

即。

// from inside the setInterval/setTimeOut function above
if ($('.className').find(something).length !== 0)... // works just fine

当你想使用 $(this) 作为遍历的起点时,问题就来了

尝试使用 $(this) 作为起点遍历测试代码

// from inside the setInterval/setTimeOut function above
// traversing up the DOM
if($(this).parents('body').length !== 0) {
    alert('hello');
} // no alert (same with closest/parentsUntil/etc up the DOM)

// from inside the setInterval/setTimeOut function above
// traversing sideways in the DOM
if($(this).siblings('body').length !== 0) {
    alert('hello');
} // no alert (same with next/prev/etc sideways in the DOM)

// from inside the setInterval/setTimeOut function above
// traversing down the DOM
if($(this).find('body').length !== 0) {
    alert('hello');
} // no alert (same with children down the DOM)

所以从 $(this) 'body'(或其他任何东西)开始似乎不存在任何地方(向上/向下/横向),从上面的任何其他起点来看都是不正确的

我还尝试使用命名的全局函数,如:

// set outside/inside document.ready
function testCode() {
    // INSERT EXAMPLE TRAVERSING TEST-CODE FROM ABOVE HERE
}

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(testCode,10000) // no alert

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(function(){
    testCode();
},10000) // no alert

再次重申我的问题:
为什么在 jQuery 中使用 $(this) 作为起点在 setInterval/setTimeOut 中遍历 DOM(向上/向下/横向)似乎是不可能的?

什么是可能的黑客/解决方法/等。对于这种行为?

针对黑客/变通方法/等可能的非解决方案。

this answer 使用 $.proxy 仅在您使用旧版本的 jQuery 时才有效 - 但由于 as this document attests 'This API has been deprecated in jQuery 3.3'... 目前这不是一个解决方案。

bind 方法也不是,因为文档证明“从 jQuery 3.0 开始,.bind() 已被弃用”并被 on 方法取代(但我看不到我将如何在这里使用 .on() 来达到任何效果 - 但也许这只是因为我缺乏想象力)。

解决方法

这是一个基本的 this 范围问题,与 jQuery 关系不大。

最直接的方法是将 this 分配给回调外部的另一个变量:

var that = this;

setInterval(function () {
    $(that).parents();
},1000);

如果你不关心 IE,或者如果你有一个构建过程,你可以使用箭头函数,它使用 this 来自它之外的范围:

setInterval(() => {
    $(this).parents();
},1000);

我个人的偏好是完全避免使用 this,因为它所有让您感到非常悲伤的愚蠢行为。从您的示例中不清楚您的 this 值来自何处,但您可以通过以下方式避免它:

// inside .each()
$('a').each(function (_,el) {
    $(el).parents();
});

// inside event handler
$('a').on('click',function (event) {
    $(event.target).parents();
});