IE7/IE8中window.setTimeout无法使用apply/call的解决方法咨询
解决IE7/IE8中window.setTimeout无法使用call/apply的问题
这个问题在IE7/8这类老旧浏览器里确实很典型,核心原因是:window.setTimeout在IE7/8中属于浏览器宿主对象提供的方法,并非标准的JavaScript函数对象,它没有继承Function.prototype上的call和apply方法,所以直接调用会抛出"object doesn't support property or method apply"的错误。
下面给你几个可行的解决方案:
方案1:包装成普通JavaScript函数
把window.setTimeout包装在一个自定义的普通函数里,这样自定义函数就能正常使用call和apply了。如果需要处理额外参数(IE7/8原生不支持setTimeout传回调以外的参数),还可以通过闭包兼容:
function wrappedSetTimeout() { // 把arguments转成数组,方便处理参数 var args = Array.prototype.slice.call(arguments); var callback = args[0]; var delay = args[1]; var extraParams = args.slice(2); // 用闭包传递额外参数,兼容IE7/8不支持setTimeout多参数的问题 return window.setTimeout(function() { callback.apply(null, extraParams); }, delay); } // 现在就可以正常用call/apply了 var savedTimeout = wrappedSetTimeout; savedTimeout.call(window, function() { console.log("在IE7/8里正常执行了"); }, 0);
方案2:使用bind的Polyfill绑定上下文
如果需要给setTimeout绑定特定的执行上下文,可以先给Function.prototype添加bind的polyfill(IE7/8原生没有Function.prototype.bind),再绑定window.setTimeout的上下文:
// 先添加bind的polyfill,兼容IE7/8 if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== "function") { throw new TypeError("Function.prototype.bind - 要绑定的对象必须是可调用的"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply( this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)) ); }; if (this.prototype) { fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); } return fBound; }; } // 绑定window作为setTimeout的上下文 var savedWindowSetTimeout = window.setTimeout.bind(window); // 正常调用 savedWindowSetTimeout(function(){ console.log("在IE7/8里通过bind正常执行"); }, 0);
方案3:手动模拟call的行为(极简版)
如果只是简单调用不需要额外参数,也可以直接手动模拟call的逻辑,不用包装函数:
var savedWindowSetTimeout = window.setTimeout; // 直接手动传递参数,模拟call的效果 savedWindowSetTimeout(function(){}, 0);
当然这个方案只适用于不需要动态改变上下文或者传递复杂参数的场景,灵活性不如前两个方案。
内容的提问来源于stack exchange,提问作者skjindal93
相关产品推荐
相关产品推荐

