javascript setInterval和setTimeout的this问题

The "this" problem

如果你通过setTimeout函数(或其他函数,或其他情况),调用的时候this的值可能并不能像你期待的那样。这种情况已经在Javascript reference里面详细的介绍过了。


    说明    

setTimeout()函数里执行的代码是与调用setTimeout函数的执行上下文分开的。正常的方法是为被调用的函数设置this的关键字,而如果你没有为该函数设置call或者bind的话,在不严格模式下会默认this为全局变量(也可以是window)。所以调用setTimeout的时候的this值可能不同。

Note:即使在严格模式下,setTimeout回调的默认值仍然是window对象,而不是undefined。 

来看看下面的例子:

myArray = ['zero', 'one', 'two'];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"

以上的结果是因为当myMethod被调用的时候,它的this值被设置为myArray,所以在该函数里,this[sProperty]等于myArray[sProperty]。

然而,再看看下面:

setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, '1'); // prints "undefined" after 1.5 seconds
myArray.myMethod函数通过setTimeout来调用,这样当它被调用的时候,它的this值就没有设置,所以是默认值windwo对象。还有,如果没有选择将this参数传递给setTimeout,就像在forEach,reduce等数组函数中一样,如下所示,使用call来设置this变量是不起作用。

setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error


    解决方法    

一般的解决这种问题的方法是包装函数,将this设置为需要的值:

setTimeout(function(){myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(function(){myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds
箭头函数也是一个可能的选择:

setTimeout(() => {myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(() => {myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds

另一种解决"this"问题的方法是将原本的setTimeout()和setInterval()替换为允许传递this对象和通过使用Function.prototype.call设置this在回调函数中,例如:

// Enable setting 'this' in JavaScript timers
 
var __nativeST__ = window.setTimeout, 
    __nativeSI__ = window.setInterval;
 
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, 
      aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeST__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
 
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this,
      aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeSI__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};

Note:这两个替换方案也可以使HTML5标准的任意参数能通过IE的定时器的回调函数。所以它们也被用来作profills 。

有关profill,大家可以自行查阅。

替换setInterval和setTimeout后的新功能的测试:

myArray = ['zero', 'one', 'two'];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

setTimeout(alert, 1500, 'Hello world!'); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds
Note:Javascript 1.8.5 引入了Function.prototype.bind()函数来为给定函数设置this值。这样可以避免使用包装函数为设置回调中的值

使用bind()的例子:

myArray = ['zero', 'one', 'two'];
myBoundMethod = (function (sProperty) {
    console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);

myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds
翻译资料:https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout中的 The "this" problem 选段。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue.js中,你可以使用`setInterval`和`setTimeout`函数来执行定时任务。这两个函数允许你在指定的时间间隔或延迟后执行特定的代码。 1. `setInterval`函数用于创建一个定时重复执行的任务。它接受两个参数:要执行的函数和时间间隔(以毫秒为单位)。 ```javascript // 示例:每隔1秒输出一次日志 let intervalId = setInterval(() => { console.log("定时任务执行"); }, 1000); ``` 在Vue.js中,通常将`setInterval`函数与生命周期钩子函数一起使用,以便在组件挂载后开始定时任务,并在组件销毁前清除定时器。 ```javascript export default { data() { return { intervalId: null }; }, mounted() { this.intervalId = setInterval(() => { console.log("定时任务执行"); }, 1000); }, beforeDestroy() { clearInterval(this.intervalId); } }; ``` 2. `setTimeout`函数用于创建一个只执行一次的延迟任务。它接受两个参数:要执行的函数和延迟时间(以毫秒为单位)。 ```javascript // 示例:延迟2秒后输出一次日志 setTimeout(() => { console.log("延迟任务执行"); }, 2000); ``` 同样,在Vue.js中,可以将`setTimeout`函数与生命周期钩子函数一起使用,以在组件挂载后执行一次延迟任务。 ```javascript export default { mounted() { setTimeout(() => { console.log("延迟任务执行"); }, 2000); } }; ``` 请注意,在使用`setInterval`和`setTimeout`时,确保在适当的时候清除定时器,以避免内存泄漏和不必要的性能开销。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值