关于javascript:通过设计检查真正的明确性?

Is checking for true explicity bad by design?

显式检查布尔值真是否被认为是错误的?做一个简单的if(success)会更好吗?

我看过各种各样的关于if (someBoolean === true)在强类型语言中是多么可怕的代码的笑话,但是在弱类型语言中它也被认为是不好的吗?

这将适用于对if语句执行类型强制的任何弱类型语言。

一个具体的例子是:

1
2
3
4
5
6
7
8
9
var onSuccess = function (JSONfromServer) {
    // explicitly check for the boolean value `true`
    if (JSONfromServer === true) {
         // do some things
    }
}

// pass it to an ajax as a callback
doSomeAjax(onSuccess);

[编辑]

在这种特殊情况下,success变量是从服务器返回的任何有效JSON。所以它可以是任何东西。如果它是布尔值,那么就成功了。如果它是一个错误处理对象,那么它将被处理。如果它是其他东西,那么它可能会被安静地处理。

问题是让服务器将true作为json返回,并检查如何处理操作成功的情况。

不过,我想避免专门针对javascript&ajax。


有了javascript,我们就知道除了布尔值的真和假之外,值还可以是真实和不可靠的。

考虑:

1
2
3
4
5
6
if (false)     // evaluates to false.
if (0)         // evaluates to false, 0 is falsy.
if ("")        // evaluates to false, empty strings are falsy.
if (null)      // evaluates to false, null values are falsy.
if (undefined) // evaluates to false, undefined values are falsy.
if (NaN)       // evaluates to false, NaN is falsy.

对象的所有其他值都是真实的。

如果truthy和falsy值导致逻辑错误,则应考虑显式使用===!==运算符,以确保按类型和值比较对象。


我自己也有两种想法。

在一方面,由于JavaScript处理类型强制的方式,您发布的代码示例很好。只要success是真的,一个简单的if (success)就可以进入if块,例如,一个非空字符串就可以做到这一点。三重相等保证了success确实是一个布尔值true,这比使用较短的版本(也可能是您想要的版本)得到的保证更强。

但是,如果你需要这个——也就是说,你不知道success是一个布尔值,还是一个字符串,还是一个整数——我认为这本身就是一种代码味道。不管您如何进行比较,我总是将其与一个不可避免地成为布尔值的变量进行比较;此时,使用哪种比较形式并不重要,因为它们是等价的。实际上,我甚至会引入这样一个"冗余"变量:

1
2
3
4
5
var successCount = items.size(); // or some other way to get an integer
var success = successCount > 0;
if (success) {
   ...
}

所以,呃,是的。我认为没有人会因为===的功能差异而抱怨它在比较中的(明确)使用。但同样的,如果您明显使用了Boolean success标志,那么我认为也不应该有人抱怨短样式。

(不过,对于您的第一句话,我认为在动态类型语言中显式检查布尔值true并不坏,如果该值实际上是您想要的。当静态类型已经将变量约束为布尔值时,这是多余的。)


通常情况下,需要布尔变量名,如:

1
success, enabled, pass

有一个真正的价值。所以

1
2
3
4
5
6
7
if(success) //or

if(enabled) //or

if(pass) //or

if(enabled) //or

是可以理解和逻辑可读的。但是如果你有如下变量:

1
result, status, port1.bit7

最好是写:

1
2
3
4
5
if(result == true) //or

if(status == false) //or

if(port1.bit7 == true)

因为它比下面的例子更容易理解:

1
2
3
4
if(result)
{
  ....
}

可读性就是可维护性。


什么会出错?没错,没什么。在最好的情况下,您的函数什么也不做。这比把一些随机的论点当作true来接受要好。

如果您一直在使用true,那么您还应该明确检查它。

虽然我确信在python中我支持if foo:,但这里有一个很大的区别,那就是最终一些随机jquery程序员可能会来很久,并认为"哦!它还可以与字符串和new Boolean()一起使用,并使用它。

关于肖恩使用!!的建议,这实际上取决于你是否只希望一个布尔值被接受或是任何正确的东西。对于一个干净的API,我只接受布尔值。


要添加到此对话中,sessionstorage和localstorage变量今天只能存储为字符串,因此如果使用:

1
sessionStorage.setItem('completed',true);

它将实际转换为字符串并存储为"true"。我见过很多人编写方法和转换来操作这个值,这样他们就可以使用一个使用布尔值的if语句,其中

1
if sessionStorage.getItem('completed') === 'true';

在我看来,这就足够了,完全可以辨认和维护。


我读过很多关于javascript的文章,我从未见过有人说if(success)是一种糟糕的做法。我愿意这样做。您确定success参数始终是布尔值吗?现在,如果这会改变为其他东西,你就必须编辑函数。但如果您只使用if(success),它将适用于其他"真实"和"虚假"值,如字符串与空字符串,或1与0。

如果要将该参数转换为其布尔值,只需对其进行二次求反:!!success;但在这样的条件中不需要这样做。


它是代码气味还是语言气味,或者是实现细节还是约定的问题?

实际上,这取决于具体情况。

把所有的假值和真值放进一个桶中可以简化事情,直到差异变得重要为止,不管是错误的代码设计,还是因为某些原因它确实很重要。

同样,霍尔也为自己发明了null参考文献而道歉,这与我所看到的这个真实问题的根源一样接近。Javascript的设计通过添加更真实的值来解决这个问题,这使得许多人只是提倡显式检查,以避免难以跟踪的错误(Douglas Crockford)。javascript社区已经接受了语言本身,有点卡住了。python核心团队提倡相反的观点,因为语言设计似乎是建立在简化事情上,而不是混淆它们,并且核心团队仍在计划对语言进行更改。随着时间的推移,小的、迭代的变化是大的改进的本质,不管是约定的,还是语言设计的。

这两种策略都是针对特定情况的好策略。我不是说这是改进的唯一来源,但这是目前改进的主要来源。

例如,在python中,TrueFalse实际上是int的子类,具体来说是0和1。这有几个设计优点。那么,政治公众人物8的倡导者更愿意这样做

1
2
if a_reference:
    pass

在Python中,唯一真正需要使用None的时间是指定可选参数。

1
2
3
4
5
6
7
def foo(bar=optional): # NOTE I made up this idealistic construct
   """Looks good at the surface"""
    pass

def foo(bar=None):
   """But this is clear to the programmer"""
    pass

javascript隐式地将所有变量作为可选变量:

1
2
3
function foo(x, y, z) {
    // Certainly not clear to the programmer.
}

Crockford提倡明确地检查事物,以尝试为语言增加一些清晰度。

1
2
3
if (foo === undefined) {
    // pass
}

基本上,javascript添加了空引用2,称为undefined。我还认为很有趣的是,编程界对javascript语言的考虑太差了,他们认为这是一个公平的折衷,增加了使用诸如coffeescript、gwt、pyjamas之类的东西的复杂性,只是为了拥有更好的客户端语言。当然,我不同意增加的复杂性,但遗憾的是,有些人可能会受益,至少是暂时的,更快地完成手头的工作,而不是处理javascript。

不过,从长远来看,我确实认为这是一个愚蠢的决定。