Я не понимаю исходный код функции noConflict. Он находится в jQuery 3.3.1:
jQuery.noConflict = function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
};
Почему они проверяют строгое равенство между window.jQuery и jQuery? (deep && window.jQuery === jQuery)
Как window.jQuery
может содержать что-либо, кроме jQuery?
window.jQuery
может быть равен jQuery, может быть неопределенным, я думаю, но не более того. Я думаю, что другие библиотеки не помещают jQuery в объект окна.
И затем есть этот код из "Professional jQuery" (книга):
noConflict: function( deep ) {
window.$ = _$;
if ( deep ) {
window.jQuery = _jQuery;
}
return jQuery;
}
который не использует window.jQuery === jQuery.
Но в этом случае мы можем передать значение true в noConfilct, например noConfilct(true), и этого будет достаточно, чтобы перезаписать window.jQuery предыдущим значением. Нет необходимости в window.jQuery === jQuery.
Нет, если вы передадите true
и window.jQuery
(допустим, версия 2) будет нет равным jQuery
(допустим, версия 3), вы не перезапишете его. Это связано с тем, что вы могли сначала загрузить jQuery2, а затем загрузить jQuery3 и вызвать для него .noConflict
. Проблема становится очевидной, если у вас есть еще больше версий, загружающих jQuery 1, 2 и 3, тогда, если вы вызываете .noConflict
для одной, вы не обязательно хотите, чтобы она восстанавливала предыдущее значение, поскольку это зависит от порядка, в котором они были загружены.
Не будет ли разумнее, если вы спросите об этом прямо на github.com/jquery/jquery?
Это в случае загрузки нескольких версий jQuery. Давайте сделаем образец здесь
function PseudoJQuery(version) {
//keep track of version
this.version = version;
//keep previous $ and jQuery values
var _$ = window.$;
var _jQuery = window.jQuery;
//assign the current version
var jQuery = this;
window.$ = jQuery;
window.jQuery = jQuery;
//re-use the jQuery.noConflict
this.noConflict = function(deep) {
if (window.$ === jQuery) {
window.$ = _$;
}
//remove the check
if (deep /*&& window.jQuery === jQuery */) {
window.jQuery = _jQuery;
}
return jQuery;
};
}
//load multiple versions of our jQuery
var j2 = new PseudoJQuery(2);
var j3 = new PseudoJQuery(3);
console.info("version after loading", window.jQuery.version);
j2.noConflict(true);
console.info("version after noConflict", window.jQuery.version); //error
Итак, это упрощенная версия того, что jQuery делает при инициализации и что пытается восстановить при вызове noConflict
. Это терпит неудачу, потому что, когда мы вызываем j2.noConflict
, переменная window.jQuery
будет возвращена в исходное состояние — undefined
, что уничтожит установку версии 3.
С установленной проверкой версия jQuery ток уничтожит себя только при вызове noConflict
, но не при любой другой установке jQuery.
function PseudoJQuery(version) {
//keep track of version
this.version = version;
//keep previous $ and jQuery values
var _$ = window.$;
var _jQuery = window.jQuery;
//assign the current version
var jQuery = this;
window.$ = jQuery;
window.jQuery = jQuery;
//re-use the jQuery.noConflict
this.noConflict = function(deep) {
if (window.$ === jQuery) {
window.$ = _$;
}
if (deep && window.jQuery === jQuery) {
window.jQuery = _jQuery;
}
return jQuery;
};
}
//load multiple versions of our jQuery
var j2 = new PseudoJQuery(2);
var j3 = new PseudoJQuery(3);
console.info("version after loading", window.jQuery.version);
j2.noConflict(true);
console.info("version after noConflict", window.jQuery.version);
Значит, _jQuery
сохраняет свое значение даже после PseudoJQuery(2)
вызова? Это закрывающий механизм? Если бы _jQuery
было, скажем 3
, после звонка PseudoJQuery(2)
, оно все равно было бы 3
?
Да, _jQuery
виден только внутри закрытия, поэтому он не изменится после инициализации. И каждый экземпляр PseudoJQuery
имеет свою собственную копию _jQuery
. Для «версии 2» _jQuery
содержит undefined
, потому что ранее window.jQuery
ничего не присваивалось. Для «версии 3» _jQuery
содержит ссылку на «версию 2». Когда вы делаете версию 2, восстанавливаете значение, которое оно делает window.jQuery = undefined
, хотя этого не должно быть.
Извините за беспокойство, но если мы загрузим jQuery_v1, а затем jQuery_v2 и вызовем jQuery.noConflict()
, это запустит jQuery_v2 noConflict
?
@Darko да, это правильно, но у вас все еще может быть ссылка на ранее загруженную версию jQuery, например, если вы динамически загружаете библиотеки. Таким образом, вы должны загрузить v2, получить ссылку на него, загрузить v3, а затем использовать ссылку на v2 для вызова .noConflict()
. Это немного пограничный случай, но он все равно не должен сломать jQuery на странице. Одним из примеров того, как это может произойти, является ситуация, когда вы ставите в очередь некоторый асинхронный код и не уверены, когда именно каждый из них будет выполняться.
В window.jQuery === jQuery
window.jQuery
будет содержать самое последнее значение, а не значение на момент выполнения PseudoJQuery()
. А jQuery
— это частная ценность, существующая только в PseudoJQuery()
. И это значение сохраняется даже после того, как PseudoJQuery()
перестанет выполняться. Просто поправьте меня, если я ошибаюсь, и у меня больше нет вопросов.
@Darko да, window.jQuery
- это значение Один для всего, потому что оно глобальное. Таким образом, он будет содержать только одну версию jQuery — без вызова .noConflict
она будет последней загруженной. Переменная var jQuery
существует для каждого пример PseudoJQuery. Когда вы вызываете .noConfluct()
, этот метод имеет доступ только к своей собственной переменной jQuery
, и, поскольку она не открыта, ничто извне не может ее изменить.
window.jQuery может быть уже определен другой версией jQuery или чем-то подобным, если вам нужно запустить более одной версии параллельно.