提问人:Maxim Gershkovich 提问时间:9/14/2010 最后编辑:AbyxDevMaxim Gershkovich 更新时间:12/3/2018 访问量:6649
如果你的选择器对象无效,为什么jQuery不会轰炸?
Why doesn't jQuery bomb if your selector object is invalid?
问:
最近使用了一些代码,大致如下
$("#divMenuContainer:visible").hide("explode");
然而,在花了一些时间试图让它工作之后,我意识到我的选择器引用了一个不存在的 div。
查询的结果只是它没有执行。
显然这是设计使然,谁能解释为什么做出这种设计选择而不是提出某种例外的逻辑?
不是试图批评,只是试图理解。
答:
这是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
评论
因为在jQuery中仍然返回一个“空”jQuery,并且所有jQuery对象都有自己的方法,所以没有错误。$("#thisdivdoesntexist")
Object
这其实是一件好事。如果这会引发错误,那么在执行某些操作之前,在很多情况下都需要进行一些额外的检查,这意味着您将有很多“重载”代码。尽管在对对象调用方法之前检查它是否存在并不是坏习惯,但当选择器不返回任何内容时,并非所有 JavaScript 都会停止(如果它抛出错误,就会发生这种情况)
因此,即使某些页面没有选择器,您也可以全局使用选择器,而不必担心这一点。
评论
$('something')
$("#thisdivdoesntexist")
jQuerys constructor function
我认为这可能与您的选择器以下事实有关:
$("#divMenuContainer:visible")
在幕后返回一个 jQuery 对象,其中包含许多可能的匹配项。然后对其中每个执行隐藏功能。我想在这种情况下不抛出异常是有一定道理的,因为你有一个条目为零的列表,而不是得到一个空值。
不引用任何元素的选择器仍然是合法的选择器,它可能是有意的。给定的选择器有时可能会返回元素,并且您希望能够使用这样的选择器而不会引发运行时错误。
jQuery() 将始终返回一个 jQuery 对象,以防止错误,但更重要的是:
因此,您可以编写响应式代码。
do X if Y is present
如果 Y 不存在,则不计算 X。
这意味着您可以拥有一个全局的 init 跨页面,并且无论它们是否找到某些东西,都可以使用 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();
});
当然,有些插件写得很差,会抛出错误。
这对我来说很有意义......如果你的选择器与任何元素都不匹配,你仍然可以调用所有普通的jQuery原型函数,而不会产生错误!最坏的情况是,你最终会得到一个“空”的jQuery集,将你的更改应用于任何元素。
通常,我只在元素存在时继续执行以下操作:
var aThing = $("#myElement");
if(aThing.length){
//my code here
}
这里有几个很好的理由,“可链接性”是主要驱动力,通过链接编写非常简洁的代码的能力必须不会抛出错误才能完美地工作,例如:
$("#divMenuContainer:visible").hide("explode").add("#another").fadeIn();
链中的每个对象,即使它没有引用任何 DOM 元素,也可能在以后添加更多元素,或者让我们再举一个例子:
$("#divMenuContainer:visible").live("click", function() { ... });
在这种情况下,我们不关心选择器找到的任何元素,我们关心选择器本身。这是另一个:
$("#divMenuContainer:visible").find(".child").hide("explode").end().fadeOut();
即使没有孩子,我们也可能想在之后跳回链中,继续使用引用来回到链上。.prevObject
像这样的例子有几十个不同的案例,显示了图书馆这样做的好处。至于原因,从jQuery的创建者John Resig的采访中,他说这就是它的结果。他追求的代码尽可能简洁,而链接模型就是从帽子中得出的,它恰好也有很多好处,上面的例子只是其中的一小部分。
需要明确的是,我并不是说链接的每个属性都是好的,它只是有很多好处。
让我们以这个页面为例,如果我们有这样的东西会怎样:
$(".comment").click(replyToFunction);
这应该因为还没有任何评论而失败吗?好吧,不,不是真的,这是意料之中的,我不希望这里出现错误......如果元素存在,则执行,如果不存在,则不执行。我的观点是,至少根据我的经验,不因为缺少元素而抛出错误比抛出错误更有用。
你问题中的选择器,#ID
选择器是一个非常特殊的情况,你只期望一个元素,所以也许你可以争辩说它应该在那里失败......但是,这与其他选择器不一致,并且您希望库保持一致。
对于几乎任何其他选择器,您都期望 0-many 元素,因此在大多数情况下,当您找不到任何元素时失败将大大不那么可取,在上述 .live()
等情况下更是如此。
评论
if(!$("selector").length) { }
.live()
.selector
.context
.prevObject
jQuery.fn.require = function(num, num2) { if(this.length < num) $.error("At least " + num + " elements are required"); if(num2 && this.length > num2) $.error("Between " + num + " and " + num2 + " elements required"); };
把它想象成一个查询,它就是这样。您要求提供符合您条件的所有“记录”(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>
评论
一个很好的例子是,当您想使用所有选中的复选框执行某些操作时
$("input:checked")
...你不知道检查了多少。可以是任何、全部或无。这取决于用户。
因此,不必编写像
var checkedInputs = $("input:checked");
if (checkedInputs && checkedInputs .length > 0) {
checkedInputs .doStuff();
}
你可以只是
$("input:checked").doStuff();
如果他们做出了选择,那就太好了,事情就完成了。如果不是...没有伤害,没有犯规。
评论
if()
true
if(checkedInputs.length > 0) {...
0
true
if(checkedInputs.length) {...
我猜是因为它将在前端使用 - 最终用户不应该看到异常,因为开发人员编写了一些糟糕的代码。在这种情况下,静默失败通常更安全。
这是一个灵活性问题。我自己,我想要你要求的同样的保护,你总是可以自己做。用:
jQuery.fn.single = function() {
if (this.length != 1) {
throw new Error("Expected 1 matching element, found " + this.length);
}
return this;
};
现在使用 $(“input:checked”).single() 来保证它要么返回单个项目,要么给你一个错误。
我以为它就像CSS一样,这意味着如果你试图设置一个不存在的元素的样式,你不会得到任何错误。
上一个:闭包与匿名函数(区别?[复制]
下一个:如何从前导元素和数组制作切片?
评论