我最近已经对一些已经维护了两年的旧代码进行了修改。

作为使用对话框样式面板的YAHOO YUI 2.2(是的,那很旧)的脚本的一部分,我有一个函数来监听给定面板集中3个按钮的单击事件:

addFooListeners = function (panelType) {

    YAHOO.util.Event.addListener("show" + panelType, "click", showFoo, eval(ns + ".panel_" + panelType), true);
    YAHOO.util.Event.addListener("hide" + panelType, "click", hideFoo, eval(ns + ".panel_" + panelType), true);
    YAHOO.util.Event.addListener("commit" + panelType, "click", commitFoo, eval(ns + ".panel_" + panelType), true);

}


这段代码是许多面板/对话框具有几乎相同的行为的结果。

对于这一轮开发,我已经需要添加不时做事的功能,因此我添加了一个对象overrides,它使我可以将showhidecommit操作指向其他位置。我想出了以下内容:

addFooListeners = function (panelType, overrides) {

    var handlers = {
        show: ( overrides != null ? ( overrides.show != null ? overrides.show : showFoo ) : showFoo ),
        hide: ( overrides != null ? ( overrides.hide != null ? overrides.hide : hideFoo ) : hideFoo ),
        commit: ( overrides != null ? ( overrides.commit != null ? overrides.commit : commitFoo ) : commitFoo )
    }

    YAHOO.util.Event.addListener("show" + panelType, "click", handlers.show, eval(ns + ".panel_" + panelType), true);
    YAHOO.util.Event.addListener("hide" + panelType, "click", handlers.hide, eval(ns + ".panel_" + panelType), true);
    YAHOO.util.Event.addListener("commit" + panelType, "click", handlers.commit, eval(ns + ".panel_" + panelType), true);
}


如您所见,我正在强制执行默认行为,除非overrides对象中的适当属性设置了另一个函数(命名为或

是否有一种更简洁/可读性强的方法来简洁地设置handlers对象?在我眼中,嵌套的三元似乎有点杂乱无章,但是像if ( overrides != null ) { ... }这样的其他方法似乎也很混乱。

评论

我个人的看法是?三元运算符仅在未嵌套时才值得使用。在您的情况下,这只会使代码更难以阅读和难以维护。

我喜欢格式化嵌套的三元运算符,因此它们读起来就像是多个问题:codereview.stackexchange.com/a/6562/8891

#1 楼

让我们进行一些修复。首先,这是在JS(Good Waytm)中传递可选(非布尔)参数的方式:

addFooListeners = function (panelType, handlers) {
    handlers        = handlers        || {};
    handlers.show   = handlers.show   || showFoo;
    handlers.hide   = handlers.hide   || hideFoo;
    handlers.commit = handlers.commit || commitFoo;


以上内容可以使用jQuery以更整洁的方式重写(不确定与extend等效的YUI的名称是什么):

handlers = $.extend({
    show  : showFoo, 
    hide  : hideFoo, 
    commit: commitFoo
}, handlers || {})


现在,对此代码使用eval是犯罪的。假设对象ns所指的是module,则可以代替eval来执行此操作:

YAHOO.util.Event.addListener("show" + panelType, "click", handlers.show, module["panel_" + panelType], true);
YAHOO.util.Event.addListener("hide" + panelType, "click", handlers.hide, module["panel_" + panelType], true);
YAHOO.util.Event.addListener("commit" + panelType, "click", handlers.commit, module["panel_" + panelType], true);


现在,如您所见,您将在类似的方式。您是否想在函数中定义addPanelListener函数?

function addPanelListener (event, panelType, handler) {
    YAHOO.util.Event.addListener(event + panelType, "click", handler, module["panel_" + panelType], true);
} 

addPanelListener("show"  , panelType, handlers.show);
addPanelListener("hide"  , panelType, handlers.hide);
addPanelListener("commit", panelType, handlers.commit):


希望对您有所帮助。

评论


\ $ \ begingroup \ $
+1标记将eval标记为犯罪:)我发现“ The Good Way”比jQuery更具可读性。
\ $ \ endgroup \ $
– EricBréchemier
2011年1月31日13:06

\ $ \ begingroup \ $
在我公司使用eval几乎可以保证3个小时与我见面的javascript会议:)
\ $ \ endgroup \ $
–glebm
2011年1月31日在21:25



\ $ \ begingroup \ $
aaah很好的“第一个免费”评价。很像推毒器。每当我在代码中看到该代码时,我都会感到畏缩(尤其是我在此处发布的代码;-)。
\ $ \ endgroup \ $
– LRE
2011年1月31日在21:32



\ $ \ begingroup \ $
@glebm您能详细说明什么使“好方法”成为好方法吗?
\ $ \ endgroup \ $
– LRE
2011年1月31日21:34

\ $ \ begingroup \ $
当然。它易于阅读,不易出错,而且更快。 :)
\ $ \ endgroup \ $
–glebm
2011年1月31日21:36

#2 楼

看来您可以使用&&这样减少三元数:

var handlers = {
    show:  ( overrides != null && overrides.show != null ? overrides.show : showFoo ),
    hide:  ( overrides != null && overrides.hide != null ? overrides.hide : hideFoo ),
    commit: ( overrides != null && overrides.commit != null ? overrides.commit : commitFoo )
}


我对javascript不太熟悉,但是是否需要检查function参数对空?例如,您可以通过执行以下操作来进一步缩短检查时间吗?

show:  ( overrides && overrides.show ? overrides.show : showFoo ),
hide:  ( overrides && overrides.hide ? overrides.hide : hideFoo ),
// ...


评论


\ $ \ begingroup \ $
一般来说,我认为您不需要对null进行检查是正确的-但是它可以为非null和false,然后将其评估为false(尽管在这种情况下,我认为可以)
\ $ \ endgroup \ $
– LRE
2011年1月31日,0:03

\ $ \ begingroup \ $
Overrides.show看起来可能是布尔值;如果是这样,则需要显式针对null进行测试。
\ $ \ endgroup \ $
– Fred Nurk
2011年1月31日,下午1:36

\ $ \ begingroup \ $
@Fred的目的是传递用于显示,隐藏和提交的函数。如果在此处传递了false,则将使用showFoo()。如果将true传递给了那,那么它将被代替showFoo()并引起进一步的麻烦,所以我想我需要谨慎行事。话虽这么说,但我只会在这些参数中传递一个函数,因此我现在可能会生存下来。
\ $ \ endgroup \ $
– LRE
2011年1月31日,下午1:48

\ $ \ begingroup \ $
可能值得指出的是,&&的使用仅在&&是短路和运算的情况下才有效(对于C派生的语言,但这不是所有语言的安全假设)。
\ $ \ endgroup \ $
–托德·雷曼(Todd Lehman)
2012年1月22日上午8:01

\ $ \ begingroup \ $
甚至可以更短:show:覆盖&& overlay.show || showFoo
\ $ \ endgroup \ $
–一些
2012年8月13日在22:51

#3 楼

在JavaScript中,不需要显式检查变量是否为null或未定义,因为:


null或未定义在布尔表达式中返回false。
JS表达式从左到右。因此,对于a || b,如果a为false,则仅评估b。但是,如果a为true,则不会检查b。类似地,对于a && b如果a为false,则不会评估b。因此,if (a != null) { "do something" }可以写为if (a) { "do something" }或简单地称为a && "do something"

以相同的方式可以使用在值设置为null或未定义时设置默认值:

function someFunction(age){
    :
    var age= age|| 18;
    :
}


someFunction(28)结果为28,而someFunction()结果为18。