10

jQuery を広く使用している Web サイトがあり、Firefox と IE で正常に動作します。ただし、Chrome では、頻繁に (そして半ランダムに) 取得していますUncaught TypeError: Cannot call method 'apply' of undefined(また、他の jQuery メソッドが の代わりに表示されますapply)。

問題を追跡して jQuery メソッドにたどり着きpushStack()ました。

元のソース コード (jQuery 1.7.1):

// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
   // Build a new jQuery matched element set
   var ret = this.constructor();

   // (etc.)
}

インストルメント化されたコード:

pushStack: function( elems, name, selector ) {
   if (!(this instanceof jQuery.fn.init)) throw this;

   // Build a new jQuery matched element set
   var ret = this.constructor();

   if (!(ret instanceof jQuery.fn.init)) {
          console.log("pushStack>this: " + this.constructor);
          console.log("pushStack>ret: " + ret.constructor);
          throw ret;
   }

   // (etc.)
}

ほとんどの場合pushStack()、正しく実行されます。Objectただし、Chrome は の代わりにtype のオブジェクトを作成することがありjQuery.fn.initます。コンソール出力:

pushStack>this: function ( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
    }
pushStack>ret: function Object() { [native code] }
Uncaught #<Object>

誰かが同様の問題に遭遇しましたか? それはChromeの(既知の)バグですか?

アップデート

独自にロードできるように、ページを単純化することができました。Chromium プロジェクト project のバグを埋めました。問題を再現するためのページがそこに添付されています。

4

2 に答える 2

11

Chromiumバグトラッカーの応答は、これがChromeブラウザのバグであることを確認しているようです。

pushStack()回避策は、jQueryの関数を「修正」することです。

// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
   // Build a new jQuery matched element set
   var ret = this.constructor();

   // Workaround for Chrome bug
   if ((this instanceof jQuery.fn.init) && !(ret instanceof jQuery.fn.init)) {
       // console.log("applying pushStack fix");
       ret = new jQuery.fn.init();
   }

   // etc.
}
于 2012-05-23T17:32:22.810 に答える
5

これは「目立たない」ソリューションです (たとえば、CDN から jQuery をプルする場合)。これを .js ファイルに保存し、jQuery をプルした後にインクルードします。

(function ($) {
    var pushStackOrig, pushStackChrome;

    pushStackOrig = $.fn.pushStack;

    pushStackChrome = function ( elems, name, selector ) {
        // Build a new jQuery matched element set

        // Invoke the correct constructor directly when the bug manifests in Chrome.
        //var ret = this.constructor();
        var ret = new jQuery.fn.init(); 

        if ( jQuery.isArray( elems ) ) {
            push.apply( ret, elems );

        } else {
            jQuery.merge( ret, elems );
        }

        // Add the old object onto the stack (as a reference)
        ret.prevObject = this;

        ret.context = this.context;

        if ( name === "find" ) {
            ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
        } else if ( name ) {
            ret.selector = this.selector + "." + name + "(" + selector + ")";
        }

        // Return the newly-formed element set
        return ret;
    };

    $.fn.pushStack = function (elems, name, selector) {
        var ret;

        try {
            ret = pushStackOrig.call(this, elems, name, selector);
            return ret;
        } 
        catch (e) {
            if (e instanceof TypeError) {
                if (!(ret instanceof jQuery.fn.init)) {
                    ret = pushStackChrome.call(this, elems, name, selector);
                    return ret;
                }
            }

            throw e;
        }
    };

}).call(this, jQuery);
于 2012-05-23T21:12:08.163 に答える