Почему jQuery не работает, если ваш объект-селектор недействителен?

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

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

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

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

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

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

Ответ 1

Здесь есть несколько веских причин: "цепочки" является основным диском, способность писать очень краткий код путем цепочки не должна бросать никаких ошибок, чтобы работать без видимых проблем, например:

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

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

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

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

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

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

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

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


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

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

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

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

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

Ответ 2

Подумайте об этом как о запросе, который он есть. Вы запрашиваете все "записи" (элементы 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>

Ответ 3

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

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

    return this;
};

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

Ответ 4

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

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

do X if Y is present

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

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

$(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

Это часть jQuerys (на самом деле John Resigs, я думаю), философия о библиотеке.

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

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

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

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

Ответ 6

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

Ответ 7

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

$("input:checked")

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

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

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

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

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

И если они сделали выбор, здорово, все будет сделано. Если нет... никакого вреда, не фола.

Ответ 8

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

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

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

Ответ 9

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

var aThing = $("#myElement");
if(aThing.length){
    //my code here
}

Ответ 10

Я думаю, что это, вероятно, связано с тем, что ваш селектор:

$("#divMenuContainer:visible")

Под обложками возвращается объект jQuery, содержащий количество возможных совпадений. Затем функция "Скрыть" выполняется по каждому из них. Я полагаю, что исключение исключения в этом случае не делает определенного смысла, поскольку у вас есть список с нулевыми элементами, вместо того, чтобы возвращать нуль.

Ответ 11

Это просто имеет смысл для меня... Если ваш селектор не соответствует ни одному элементу, вы все равно можете вызвать все обычные функции прототипа jQuery без возникновения ошибок! В худшем случае вы получаете "пустой" набор jQuery, применяя ваши изменения к никаким элементам.

Ответ 12

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

Ответ 13

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