面试题:
写一个 setInterval(fn, a, b),每次间隔 a,a+b,a+2b,....,a+nb调用fn,然后写一个 clear函数,清除setInterval函数。
思路:使用setTimeout函数计时,重复调用可以考虑使用循环语句,或者我们也可以使用递归调用,那就需要添加条件判断了,不然会导致栈溢出,但是由于此处是setTimeout函数,调用递归函数会有时间延迟,所以不会导致立即导致栈溢出,因此我们可以不用写条件判断,setInterval函数就写完了,剩下的就是写clear函数了。
function setInterval(fn, a, b) { let n = 0 let timer function loop() { timer = setTimeout(function() { fn() n++ loop() }, a + n*b) } loop() return timer } let time = setInterval(()=>{console.log('tes')}, 1000, 2000)
上面的代码完成了间隔调用函数fn的功能,没有完成clear函数的功能
完整的解决方法可以参考此链接
setTimeout函数的实际应用:
案例引自MDN:给不支持setTimeout添加第三个参数的IE9打补丁。
setTimeout(function(arg1) { if (arg1 === 'test') { // 检测原生的setTimeout是否支持传入第三个参数 return; } // __natuveST__ 指原生的setTimeout var __nativeST__ = window.setTimeout; window.setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) { // 从arguments第三个参数开始拷贝并赋值给aArgs var aArgs = Array.prototype.slice.call(arguments, 2); // 检测vCallback是否是函数 return __nativeST__(vCallback instanceof Function ? function() { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; }, 0, 'test');
如何解决setTimeout的this指向问题:(默认情况下回调函数的this指向全局对象)
1.可以在回调函数外层包裹一个匿名函数,来创建新的执行环境
function test() { return console.log(this) } const o = {} o.test = test // 我们希望返回的是o这个对象 setTimeout(o.test, 2000) // window
修改后的代码:
function test() { return console.log(this) } const o = {} o.test = test setTimeout(()=>{o.test()}, 2000) // {test: f}
2. 修改原生setTimeout函数的this指向
let newSetTimeout = window.setTimeout window.setTimeout = function (callback, delay) { let args = Array.prototype.slice.call(arguments, 2), _this = this return newSetTimeout( callback instanceof Function ? function(){callback.apply(_this, args)} : callback, delay) }
3.在回调函数上使用bind函数修改this指向
function test() { return console.log(this) } const o = {} o.test = test setTimeout(o.test.bind(o), 2000) // {test: f}