Internet Explorer 7/8 and window functions are empty objects

In Internet Explorer 8 (also works in IE9 in IE7 / 8 modes), the following codes warn object and undefined instead of the 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: http://jsfiddle.net/BsvZw/5/

Why is this happening? What will be the 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 }; 
+4
source share
2 answers

Why is this happening?

Basically, since IE hates web developers and messes with you.

More seriously, things provided by a browser implementation that are not part of the core Javascript language can be classified as host objects . When it comes to host objects, all bets are disabled, and they are basically allowed to do whatever they want, [1] ignoring the usual Javascript semantics.

What will be the workaround to get the actual setTimeout?

I know that it is really ugly, but you can chain if-else-if to a predetermined number of arguments. In the case of setTimeout, this should not be a big problem, since you do not need more than two or three arguments.

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

Although this is a very ugly solution, sometimes this is the only way. For example, there is no way to call constructors with variable arguments.


[1] To give you an idea of ​​how evil host objects can be, the other day I had to perform function 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 the nodes are host objects in IE, and just accessing the selectNodes property actually calls it, which gives me an exception of the "wrong number of arguments "!

+8
source

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

We basically force the use of Function.prototype.apply instead of looking for a nonexistent setTimeout.apply . In the call parameters, the first argument is the function that we want to run using apply (the context of the object, which in this case is setTimeout ). The following are the parameters that pass through apply , the first of which is the wait for this , the function will be run at ("null" in this case, since setTimeout does not allow the context of this value), and the next is an array of arguments to pass to the function that we want to run.

This works in IE7 +, except that IE7 does not pass user parameters (for example, "abc" in this example, which will request "undefined").

The TypeScript implementation is implemented here:

 /** Helps support cases where 'apply' is missing for a host function object (ie 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 basic JavaScript:

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

All Articles