admin管理员组

文章数量:1333390

In Internet Explorer 8 (works also in IE9 in IE7/8 modes) the following code alerts object and undefined instead of expected function and something like function() { [native code] }.

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

Try it: /

Why is this happening? What would be a workaround to get the actual setTimeout?

Update

I am trying to create a wrapper around 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
};

In Internet Explorer 8 (works also in IE9 in IE7/8 modes) the following code alerts object and undefined instead of expected function and something like function() { [native code] }.

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

Try it: http://jsfiddle/BsvZw/5/

Why is this happening? What would be a workaround to get the actual setTimeout?

Update

I am trying to create a wrapper around 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
};
Share Improve this question edited Jul 23, 2012 at 20:26 Loki Kriasus asked Jul 23, 2012 at 20:14 Loki KriasusLoki Kriasus 1,30110 silver badges24 bronze badges 5
  • what are you trying to acplish? – Ibu Commented Jul 23, 2012 at 20:17
  • Do you need this to stop the setTimeout? – davidbuzatto Commented Jul 23, 2012 at 20:19
  • @lbu, I am trying to replace setTimeout with a wrapper. I'll update the question. – Loki Kriasus Commented Jul 23, 2012 at 20:21
  • 1 @Alfabravo: apply is cross browser. The problem is that some "functions" are not actually functions in IE. – hugomg Commented Jul 23, 2012 at 20:41
  • @missingno Well, I just checked out IE docs but I'll stand corrected :) – Alfabravo Commented Jul 23, 2012 at 20:43
Add a ment  | 

2 Answers 2

Reset to default 9

Why is this happening?

Basically, because IE hates web developers and is messing with you.

More seriously, things provided by the browser implementation that are not part of the core Javascript language may be classified as host objects. When it es to host objects all bets are off and they are basically allowed to do anything they want[1] without needing to respect usual Javascript semantics.

What would be a workaround to get the actual setTimeout?

I know its really ugly, but you could do an if-else-if chain up to a predefined number of arguments. In setTimeout's case this shouldn't be a big problem since you shouldn't ever need more then 2 or 3 arguments for it.

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);
   }
};

While this is a very ugly solution, sometimes its the only way. For example, there is no way to invoke constructors with variadic arguments either.


[1] To give you an idea of how evil host objects can be, the other day I had to do feature detection for XPath methods in DOM nodes/documents. Instead of the usual if(node.selectNodes) test I had to use if("selectNodes" in node) because nodes are host objects in in IE and just accessing the selectNodes property would actually call it, giving me an "incorrect number of arguments" exception!

When you call "apply" on a function, the function object itself is the "this" of the call to "apply", so you can do 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.

Basically, we are forcing the use of Function.prototype.apply instead of trying to look for a non-existing setTimeout.apply. In the parameters to call, the first argument is the function we want to run using apply (the object context, which is setTimeout in this case). What follows next are the parameters that get pass to apply, the first of which is the expect this the function will be run under ('null' in this case, since setTimeout does not allow a this context value), and the following being the array of arguments to be passed to the function we want to run.

This works in IE7+, except IE7 doesn't pass on the custom parameters (i.e 'abc' in this example, which will prompt "undefined" instead).

Here's a TypeScript implementation:

/** 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);
    }
}

... and a basic JavaScript one:

function apply(func, _this, args) {
    if (func.apply) {
        return func.apply(_this, args);
    } else {
        return Function.prototype.apply.call(func, _this, args);
    }
}

本文标签: javascriptInternet Explorer 78 and window functions are empty objectsStack Overflow