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言語の一部ではないブラウザ実装によって提供されるものは、ホストオブジェクトとして分類される場合があります。ホストオブジェクトに関しては、すべての賭けは無効であり、基本的には、通常のJavascriptセマンティクスを尊重する必要なしに、必要なことを何でも実行できます[1] 。

実際の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メソッドの機能検出を行う必要がありました。ノードはIEのホストオブジェクトであり、selectNodesプロパティにアクセスするだけで実際に呼び出され、「引数の数が正しくない」という例外が発生するため、通常のif(node.selectNodes)テストの代わりに使用する必要がありました。if("selectNodes" in node)

于 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.

Function.prototype.apply基本的に、存在しないものを探す代わりに、の使用を強制していますsetTimeout.apply。のパラメータcallで、最初の引数は、使用して実行する関数apply(この場合はオブジェクトコンテキストsetTimeout)です。次に続くのは、に渡されるパラメーターですapply。最初のパラメーターは、関数が実行されることを期待します(この場合、コンテキスト値を許可しないため、this「null」 )。次は、への引数の配列です。実行したい関数に渡されます。setTimeoutthis

これはIE7+で機能しますが、IE7はカスタムパラメーターを渡しません(つまり、この例では「abc」で、代わりに「undefined」というプロンプトが表示されます)。

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 に答える