Почему jQuery не бомбит, если ваш объект селектора недействителен? - PullRequest
72 голосов
/ 14 сентября 2010

Недавно использовал какой-то код в стиле

$("#divMenuContainer:visible").hide("explode");

Однако после некоторого времени, потраченного на то, чтобы заставить его работать, я понял, что мой селектор ссылается на несуществующий div.

Результатом запроса было то, что он не был выполнен.

Очевидно, что это намеренно, кто-нибудь может объяснить логику того, почему был сделан этот дизайн, а не выдвигать какое-то исключение?

Не пытаться критиковать, просто пытаться понять.

Ответы [ 13 ]

56 голосов
/ 14 сентября 2010

Думайте об этом как о запросе , которым он является. Вы запрашиваете все «записи» (элементы DOM), которые соответствуют вашим критериям. Результатом является набор нулевых записей.

Затем он перебирает ваши нулевые записи и применяет к ним действие. :)

Если бы вы сделали то же самое с SQL или массивом, он бы вел себя одинаково в большинстве языков. Набор нулевых записей не является состоянием ошибки.

var things = $("invalid selector");
$("p").text("The object is valid: " + things + " but has " + things.length + " elements.")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p></p>
52 голосов
/ 14 сентября 2010

Здесь есть несколько веских причин: «цепочечность» - это основной диск, способность писать очень краткий код с помощью цепочек не должна вызывать ошибок, чтобы работать без всяких проблем, например:

$("#divMenuContainer:visible").hide("explode").add("#another").fadeIn();

Каждыйобъект в цепочке, даже если он не ссылается ни на один из элементов DOM, возможно, будет добавлен еще позже, или давайте возьмем другой пример:

$("#divMenuContainer:visible").live("click", function() { ... });

В этом случае нас не волнует ни один из элементов, найденных селектором,мы заботимся о самом селекторе.Вот еще одно:

$("#divMenuContainer:visible").find(".child").hide("explode").end().fadeOut();

Даже если нет детей, мы можем захотеть вернуться обратно в цепочку, продолжая использовать ссылку .prevObject, чтобы вернуться вверх по цепочке.

Существуют десятки различных случаев, подобных этому, которые показывают преимущества библиотеки в том виде, в каком она есть.Что касается почему , из интервью Джона Резига , который является создателем jQuery, он утверждает, что именно так все и получилось.Он был настолько кратким, насколько он мог понять код, и модель цепочки - это то, что вышло из-под контроля, просто она также имеет много преимуществ, приведенный выше пример - лишь некоторые из них.

Чтобы быть ясным, я не говорю, что каждый атрибут цепочки - хороший, у него просто много плюсов.


Давайте возьмем эту страницу в качестве примера,что если бы у нас было что-то вроде этого:

$(".comment").click(replyToFunction);

Если потерпит неудачу, потому что еще нет комментариев?Ну, нет, не совсем, это ожидаемо, я бы не хотел ошибки здесь ... если элемент существует, сделайте это, если нет.Моя точка зрения, по крайней мере, по моему опыту, , а не , выдавая ошибку из-за пропущенного элемента, чрезвычайно полезнее, чем выбрасывание одного.

Селектор в вашем вопросе, #ID селектор - это особый случай, когда вы ожидаете только один элемент, так что, возможно, вы могли бы поспорить, что он может там потерпеть неудачу ... но тогда это не будет соответствовать другим селекторам, и вы хотите, чтобы библиотека былапоследовательны.

С почти любым другим селектором вы ожидаете 0-много элементов, поэтому сбой, когда вы не найдете никаких элементов, будет значительно менее желательным в большинстве ситуаций, особенно в случаяхкак .live() выше.

8 голосов
/ 15 сентября 2010

Это вопрос гибкости.Я сам хотел бы получить те же средства защиты, о которых вы просите, вы всегда можете сделать это сами.Используйте:

jQuery.fn.single = function() {
    if (this.length != 1) {
        throw new Error("Expected 1 matching element, found " + this.length);
    }

    return this;
};

и теперь используйте $ ("input: selected"). Single () с уверенностью, что он либо возвращает один элемент, либо выдает ошибку.

6 голосов
/ 14 сентября 2010

jQuery () всегда будет возвращать объект jQuery, чтобы предотвратить ошибки, но что более важно:

Таким образом, вы можете написать отзывчивый код.

do X if Y is present

Если Y отсутствует, X не вычисляет.

Это означает, что у вас могут быть глобальные страницы инициализации и просто плагины инициализации, если они что-то находят или нет.

$(function(){
    // does nothing if the page contains no element with className 'accordion'
    $('.accordion').implementAccordion();
    // usually on a single page, but we can add it to a global js file nontheless.
    $('.validate-form').implementFormValidator();
});

Хотя, конечно, некоторые плагины действительно плохо работают.написано и выдаст ошибку.

5 голосов
/ 14 сентября 2010

Это часть философии jQuerys (я полагаю, Джона Резига) о библиотеке.

Он пытается быть «добрым» для вас и ваших клиентов, что, в свою очередь, означает, что он будет генерировать исключения довольно редко
(вроде очень редко)

Но, как всегда, вы можете легко расширить его как:

(function(_jQuery){
    jQuery = function(){
        var ret = _jQuery.apply(this, arguments);
        if(!ret.length) throw new Error('empty selector');
        return ret;
    };
}(jQuery));

Но, как сказано в комментарии Nick, в большинстве случаев это , а не желаемое поведение. В любом случае, если вы хотите получить его по какой-либо причине, фрагмент кода, подобный приведенному выше, должен это сделать.

3 голосов
/ 14 сентября 2010

Хороший пример - когда вы хотите что-то сделать со всеми отмеченными флажками

$("input:checked")

... вы не знаете, сколько проверено.Может быть любой, все или нет.Это зависит от пользователя.

Таким образом, вместо того, чтобы писать код вроде

var checkedInputs = $("input:checked");
if (checkedInputs  && checkedInputs .length > 0) {
      checkedInputs .doStuff();
}

Вы можете просто

$("input:checked").doStuff();

И если они сделали выбор, отличновсе сделано.Если нет ... нет вреда, нет фола.

3 голосов
/ 14 сентября 2010

Селектор, который не ссылается на какие-либо элементы, все еще является легальным селектором и может быть преднамеренным.Может случиться так, что данный селектор будет иногда возвращать элементы, и вы захотите иметь возможность использовать такой селектор без возможности выбросить ошибки времени выполнения.

2 голосов
/ 14 сентября 2010

, поскольку $("#thisdivdoesntexist") в jQuery по-прежнему возвращает «пустой» jQuery Object, и у всех объектов jQuery есть свои методы, поэтому ошибок нет.

это на самом деле хорошая вещь.Если это приведет к ошибке, во многих случаях вам понадобятся дополнительные проверки, прежде чем что-то делать, а это значит, что у вас будет много кода «перегрузки».хотя было бы неплохо проверить, существует ли он перед вызовом метода объекта, когда селектор ничего не возвращает, не весь javascript будет остановлен (что случится, если он выдаст ошибку)* следовательно, вы можете использовать селекторы глобально, даже если на некоторых страницах нет селектора, не беспокоясь об этом.

1 голос
/ 14 сентября 2010

Обычно я продолжаю, только если элемент (ы) существуют, делая что-то вроде:

var aThing = $("#myElement");
if(aThing.length){
    //my code here
}
0 голосов
/ 20 сентября 2010

Я думал, что это будет похоже на CSS, то есть, если вы пытаетесь стилизовать элемент, который не существует, вы не получите ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...