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

jQuery traversing the DOM using $(this) as a starting point inside setInterval/setTimeOut function?

我一直在尝试了解如何(在 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' 开始(或与此相关的任何其他内容)似乎不存在于任何地方 (up/down/sideways) 这从上面的任何其他起点都不成立

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

// 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 (up/down/sideways)?

什么是可能的hacks/work-arounds/etc。对于这种行为?

可能的 none-hacks/work-arounds/etc 的解决方案。

this answer using $.proxy only works if you use an older version of jQuery - but since as this document attests 'This API has been deprecated in jQuery 3.3'...目前这不是解决方案。

而且 bind method since as the document attests 'As of jQuery 3.0, .bind() has been deprecated' and been superseded by the 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();
});