4

在 Internet Explorer 8 中(在 IE7/8 模式下也可以在 IE9 中工作)下面的代码警告objectundefined而不是预期的function和类似function() { [native code] }.

alert("typeof window.setTimeout = " + typeof window.setTimeout);  // object
alert("window.setTimeout.apply  = " + window.setTimeout.apply );  // undefined

试试看:http: //jsfiddle.net/BsvZw/5/

为什么会这样?获得实际的解决方法是什么setTimeout

更新

我正在尝试创建一个包装器setTimeout

var _oldSetTimeout = window.setTimeout;
window.setTimeout = function ()
{
    // ...

    return _oldSetTimeout.apply(this, arguments);    // this is place where IE 7/8 says 'Object doesn't support this property or method'
                                                // and _oldSetTimeout looks like an empty object
};
4

2 回答 2

9

为什么会这样?

基本上,因为 IE 讨厌 Web 开发人员并且在惹你。

更严重的是,浏览器实现提供的不属于核心 Javascript 语言的东西可能被归类为宿主对象。当涉及到宿主对象时,所有的赌注都被取消了,他们基本上可以做任何他们想做的事情[1]而无需尊重通常的 Javascript 语义。

获得实际 setTimeout 的解决方法是什么?

我知道它真的很难看,但是您可以将 if-else-if 链接到预定义数量的参数。在 setTimeout 的情况下,这应该不是什么大问题,因为您不需要超过 2 或 3 个参数。

var _oldSetTimeout = window.setTimeout;
window.setTimeout = function (a1, a2, a3)
{
   switch(arguments.length){
       case 0:  return _oldSetTimeout();
       case 1:  return _oldSetTimeout(a1);
       case 2:  return _oldSetTimeout(a1, a2);
       default: return _oldSetTimeout(a1, a2, a3);
   }
};

虽然这是一个非常丑陋的解决方案,但有时它是唯一的方法。例如,也无法使用可变参数调用构造函数。


[1] 为了让您了解宿主对象的邪恶程度,前几天我不得不对 DOM 节点/文档中的 XPath 方法进行特征检测。if(node.selectNodes)而不是我必须使用的通常测试,if("selectNodes" in node)因为节点是 IE 中的主机对象,并且仅访问 selectNodes 属性实际上会调用它,给我一个“参数数量不正确”的异常!

于 2012-07-23T20:57:28.133 回答
4

当你在函数上调用“apply”时,函数对象本身就是调用“apply”的“this”,所以你可以这样做:

function test(s) { alert(""+s); }
Function.prototype.apply.call(setTimeout, null, [test, 0, 'abc']);
// Note: same as "setTimeout.apply(null, [test, 0, 'abc']);" in supported browsers.

基本上,我们是在强制使用 ofFunction.prototype.apply而不是试图寻找一个不存在的setTimeout.apply. 在 to 的参数中call,第一个参数是我们想要运行的函数apply(在这种情况下是对象上下文setTimeout)。接下来是传递给 的参数,其中第一个是函数将在其下运行apply的期望(在这种情况下为'null',因为不允许上下文值),以下是参数数组传递给我们要运行的函数。thissetTimeoutthis

这在 IE7+ 中有效,除了 IE7 不传递自定义参数(即本例中的“abc”,它将提示“未定义”)。

这是一个 TypeScript 实现:

/** Helps support cases where 'apply' is missing for a host function object (i.e. IE7 'setTimeout', etc.).  This function
* will attempt to call '.apply()' on the specified function, and fall back to a work around if missing.
* @param {Function} func The function to call '.apply()' on.
* @param {Object} _this The calling object, which is the 'this' reference in the called function (the 'func' argument).
* Note: This must be null for special host functions, such as 'setTimeout' in IE7.
* @param {any} args The arguments to apply to given function reference (the 'func' argument).
*/
function apply(func: Function, _this: Object, args: any[]): any {
    if (func.apply) {
        return func.apply(_this, args);
    } else {
        return Function.prototype.apply.call(func, _this, args);
    }
}

...和一个基本的 JavaScript:

function apply(func, _this, args) {
    if (func.apply) {
        return func.apply(_this, args);
    } else {
        return Function.prototype.apply.call(func, _this, args);
    }
}
于 2013-12-23T23:11:47.150 回答