javascript 如何通过“setInterval”快速传递范围

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3488591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 01:18:50  来源:igfitidea点击:

How to kick-ass pass scope through "setInterval"

javascriptmemory-leaksscopesetintervallambda

提问by PenthousePauper

I'm currently wondering if there is a better solution than passing thisscope to the lambda-function via the parameter 'e'and then passing it to 'funkyFunction' using call()-method

我目前想知道是否有比通过参数“e”将此范围传递给 lambda 函数然后使用 call() 方法将其传递给“funkyFunction”更好的解决方案

setInterval(function(e){e.funkyFunction.call(e)}, speed, this)

(Minor question aside: I'd been reading something about memory-leaks in javascript. How does the lambda-function affect my memory? Is it better to define it first like var i = function(e)...and then passing it as a parameter to setInterval?)

(抛开小问题:我一直在阅读有关 javascript 中内存泄漏的一些内容。lambda 函数如何影响我的内存?最好先定义它var i = function(e)...,然后将其作为参数传递给 setInterval?)

采纳答案by meder omuraliev

What's wrong with simply relying on the outer-scope defined variable?

仅仅依赖外部作用域定义的变量有什么问题?

(function() { 

    var x = {};
    setInterval(function() {
       funkyFunction.call(x)
    }, speed);

})();

回答by Hymansonkr

My situation may have been a bit different, but here's what I did:

我的情况可能有点不同,但这是我所做的:

var self = this;
setInterval(function() { self.func() }, 50);

My scenario was that my code was inside a class method and I needed to keep correct scope as I didn't want the 'this' binding to resolve to the current window.

我的情况是我的代码在一个类方法中,我需要保持正确的范围,因为我不希望“this”绑定解析为当前窗口。

eg. I wanted to run MyClass.animate from MyClass.init using setInterval so I put this scope-keep code into MyClass.init

例如。我想使用 setInterval 从 MyClass.init 运行 MyClass.animate 所以我把这个范围保持代码放入 MyClass.init

回答by CORSAIR

You can use native bind function.

您可以使用本机绑定功能。

function Loop() {
    this.name = 'some name for test';
    setInterval( (function(){//wrap the function as object
        //after bind, "this" is loop refference
        console.log(this);
    }).bind(this), 1000 );// bind the object to this (this is Loop refference)
}

var loop = new Loop();

paste this example in the console to see the result

将此示例粘贴到控制台中以查看结果

回答by NDM

I had the same question, but there seems to be no built in solution, so here is a quick workaround I punched together:

我有同样的问题,但似乎没有内置的解决方案,所以这是我一起打的快速解决方法:

function setScopedInterval(func, millis, scope) {
    return setInterval(function () {
        func.apply(scope);
    }, millis);
}

usage:

用法:

function MyClass() {
    this.timer = null;
    this.myFunc = function() { console.log('do some stuff'); };
    this.run = function() {
        this.timer = setScopedInterval(function () { this.myFunc(); }, 1000, this);
    };
    this.stop = function() { clearInterval(this.timer); };
}
var instance = new MyClass();
instance.run(); // will log to console every second
// until this line is called
instance.stop();

This only covers the use-case where you pass an actual function, not a string of code to be executed.

这仅涵盖您传递实际函数的用例,而不是要执行的代码字符串。

As for your question about memory leaks when using this functionality: it is not so much the problem with using setIntervalas it is with anonymous functions in itself. If you use a reference to an object inside a lambda, this reference will keep the referenced object in memory for as long as the anonymous function exists. I think the function is destroyed with a call to clearInterval.

至于您在使用此功能时有关内存泄漏的问题:与其说是使用问题,setInterval不如说是使用匿名函数本身。如果您在 lambda 中使用对对象的引用,则只要匿名函数存在,此引用就会将引用的对象保留在内存中。我认为该函数通过调用clearInterval.

I don't think there is any benefit from assigning the function to a variable first, on the contrary, it will create another variable containing a reference that will not be garbage collected as long as the anon func exists...

我认为首先将函数分配给变量没有任何好处,相反,它会创建另一个包含引用的变量,只要 anon func 存在,该变量就不会被垃圾收集......

回答by PapaKai

You may also have a look at the YUIFramework. It's fine for building applications and easy to learn.

您也可以查看YUIFramework. 它非常适合构建应用程序并且易于学习。

YUI2: YAHOO.lang.later(when, scope, fn, args, periodic);

YUI3: Y.later(when, scope, fn, args, periodic);

UPDATEas example

以更新为例

Using YUI and jQuery (Do not forget enable $.noConflict())

使用 YUI 和 jQuery(不要忘记启用 $.noConflict())

var jQuerySelector = jQuery("div[class^='form-field-']");

jQuerySelector.hide();
jQuery(jQuerySelector[0]).show();


YAHOO.lang.later(5000, jQuery, function(jQuerySelector) {
    if((!(this.index)) || (this.index == (jQuerySelector.length))) {
        this.index = 0;
    }

    jQuerySelector.hide();

    this(jQuerySelector[this.index++]).show();
}, jQuerySelector, true);

In short

简而言之

  • 1o parameter: 5000on every 5000 miliseconds, 3o parameter (a function) will be executed
  • 2o parameter: jQueryObject in which will be referenced by using this
  • 3o parameter: functionwhich will be executed. It receives as parameter either an array or an object passed as 4o parameter
  • 5o parameter: trueif true, executes continuously at supplied interval until canceled
  • 1O参数:5000上每5000毫秒,10-30参数(的函数)将被执行
  • 2o 参数:jQuery对象,将在其中使用this
  • 3o 参数:将要执行的函数。它接收作为参数的数组或作为 4o 参数传递的对象
  • 5o 参数:true如果为 true,则以提供的时间间隔连续执行直到取消

see http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_later

http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_later

UPDATENo need for $.noConflict() because YUI does not use $ in any way.

更新不需要 $.noConflict() 因为 YUI 不以任何方式使用 $。

回答by Tyler V.

There are two important distinctions to make.

有两个重要的区别。

1) Do you want a reference to the passed parameter so that the timeout function can track changes made to it, or do you want a clone of the passed parameter?

1) 您是否需要对传递参数的引用,以便超时函数可以跟踪对其所做的更改,还是需要传递参数的副本?

2) Do you want to be able to capture a reference to the timeout in case you want to cancel it? (Yes!)

2) 如果您想取消超时,您是否希望能够捕获对超时的引用?(是的!)

// Normal setTimeout: retains a reference to `test` and returns the bad value
var test = 'test: good';
var timer = setTimeout(function() { console.log(test); }, 1000);
test = 'test: bad';

// Test2 receives a clone of `test2` and returns the good value, but does so right away, not on a timeout
var test2 = 'test2: good';
var timer2 = setTimeout((function() { console.log(test2); })(test2), 1000);
test2 = 'test2: bad';

// Test3 receives a clone of `test3` and returns the good value, but doesn't return a reference to the timeout, and can't be canceled
var test3 = 'test3: good';
var timer3 = function(test3) { setTimeout(function() { console.log(test3); }, 1000); }(test3);
test3 = 'test3: bad';

// Test4 receives a clone of `test4` and returns the good value, and correctly returns timeout reference
var test4 = 'test4: good';
var timer4 = function(test4) { return setTimeout(function() { console.log(test4); }, 1000); }(test4);
test4 = 'test4: bad';

// Test5 retains a reference to `test5` and returns the bad value
var test5 = 'test5: good';
var timer5 = setTimeout((function() { console.log(test5); }).bind(test5), 1000);
test5 = 'test5: bad';

// Did we capture references to the timeouts?
console.log(typeof timer);
console.log(typeof timer2);
console.log(typeof timer3);
console.log(typeof timer4);
console.log(typeof timer5);