質問

I have a userscript containing this:

// userscript header
(function() {
    // here is jquery source code
    var $ = $.noConflict();
})();

The site I'm using it on, is using mootools, so the site's code depends on $. The noConflict doesn't help in Firefox (23.0.1) for some weird reason. The site still gets jQuery in $, which breaks site's original functionality.

However, when I change it to: var $ = jQuery.noConflict();

It works. Why?

I can't put userscript on jsfiddle, so here is a gif with all the code (HTML on left, userscript on right), showing the problem:

jQuery.noConflict weird behavior

Versions: everything is latest, Firefox 23.0.1, Greasemonkey 1.11, jQuery v1.10.2, Mootools 1.4.5-nc

"Bug" does not happen in: Chrome 29.0.1547.66m, Opera 12.16

役に立ちましたか?

解決

Let's see how noConflict() is actually implemented...

if ( window.$ === jQuery ) {
  window.$ = _$; // where $_ is window.$ before jquery reassigns it.
}

Now we need to remember that the window the user script operates on is not actually the same thing as the window the site sees. It is a sandboxed wrapper instead (at least in Greasemonkey and Scriptish). That wrapper actually hides all "expandos", i.e. added or overwritten properties on the original object.

Hence in your user script window.$ === undefined while in the actual page it is defined as that mootools helper. unsafewindow.$ is also the mootools helper, as unsafeWindow is the unwrapped page window.

Now, when your userscript includes jQuery, $ will on be set on the wrapped window. The original page window.$ is still mootools from the perspective of the website.

Next, the call to .noConflict(), as implemented above, will revert window.$ back, but on the sandbox wrapper. Hence window.$ in the user-script sandbox becomes undefined again, while the page window.$ (aka. unsafeWindow.$ in the user script sandbox) still is the moo helper (and was actually never changed).

Update: Greasemonkey actively disables these wrappers explicitly in their "no-grants" branch of createSandox() by setting wantXRays = false. I'd consider this to be a bug.

Now, that's the reason why you need .noConflict() in the first place in GM.

var $ = $.noConflict() cannot work because it is an error. The var $ will be hoisted and hence it is immediately undefined. jQuery will not actually set it (it just sets window.$, not local-scope $), and hence the $.noConflict() call becomes undefined.noConflict().

他のヒント

I am not too familiar with jQuery's noConflict() method, but I would imagine that it has to be used on the global scope.

You are using it within the scope of an anonymous function, so the noConflict() method will not have any effect on the $ declaration outside this scope.

Move the $.noConflict() line into the global scope and you should be fine:

$.noConflict();
(function() {
    ...
})();
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top