在if条件语句中分配变量,良好做法?[关闭]


112

一年前,我从Java之类的经典OO语言转移到了JavaScript。在Java中绝对不建议(甚至不正确)以下代码:

if(dayNumber = getClickedDayNumber(dayInfo))
{
    alert("day number found : " + dayNumber);
}
function getClickedDayNumber(dayInfo)
{
    dayNumber = dayInfo.indexOf("fc-day");
    if(dayNumber != -1) //substring found
    {
        //normally any calendar month consists of "40" days, so this will definitely pick up its day number.
        return parseInt(dayInfo.substring(dayNumber+6, dayNumber+8));
    }
    else return false;
}

基本上,我只是发现可以在if条件语句中为变量赋值,然后立即检查赋值是否为布尔值。

为了安全起见,我通常将其分成两行代码,先分配然后检查变量,但是现在我发现了这一点,我只是想知道在经验丰富的JavaScript开发人员眼中这是否是一种好习惯?


"The following code is definitely not recommended (or event not correct) in Java..."在JavaScript中甚至正确吗?因为据我所知,如果返回true,return parseInt(...)则返回整数(),如果返回dayNumber != -1false,则返回布尔值。
Daniel Kvist

Answers:


117

我不推荐它。问题是,它看起来像是一个常见错误,您尝试比较值,但使用单个=而不是=====。例如,当您看到以下内容时:

if (value = someFunction()) {
    ...
}

您不知道那是他们的意思,还是打算写这个:

if (value == someFunction()) {
    ...
}

如果您确实想进行分配,那么我建议您也进行显式比较:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}

1
@Matthew Crumley:这清楚地回答了我的问题。我不是通过赋值进行检查,而是在赋值后检查该值计算得出的值。这种理解对吗?
Michael Mao,2010年

1
@Michael:是的,这是正确的。添加比较基本上只会使您的意图更加清楚。
马修·克鲁姆利

4
但是,如果要测试返回布尔值的函数的失败/成功,则最后一个示例不起作用。换句话说,虽然 if (resultArr = myNeedle.exec(myHaystack)) {...}起作用,if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}但这并不是因为对resultArr的赋值始终是真实的,即使函数结果不是。如果有人使用此..构造,请记住首先声明结果变量;在if条件语句中,“ var”不合法。
Ville

3
您可以使用if (!!(value = someFunction())),但是正如您所说的,问题是您不能使用var内部,if因此您要么创建一个全局变量,要么什么都没有做,因为value无论如何您都必须在单独的行中进行声明。真可惜,我真的很喜欢C ++中的这种构造。
RIV

1
@riv,你是对的;如果函数返回布尔值(如我在上面的注释中所述),则条件条件将按预期工作。但是,如果函数返回一个布尔值(如我的示例所示),则整个构造都是荒谬的;从示例来看,显然我的思路是该函数将返回一个数组。快速测试表明条件true仅在函数返回时为true,而在所有其他情况下(包括返回数组,字符串,数字或null时),条件为false
维尔市(Ville)

27

我没有证据表明这不是好习惯。是的,它看起来像是一个错误,但是通过明智的评论可以很容易地纠正。举个例子:

if (x = processorIntensiveFunction()) { // declaration inside if intended
    alert(x);
}

为什么应该让该函数第二次运行:

alert(processorIntensiveFunction());

因为第一个版本看起来不好?我不同意这种逻辑。


32
不想挖掘旧的评论,但我不同意您的论点。可读的代码应该在不需要注释的情况下进行自我解释-将注释添加到混乱的代码中并不是补救措施。至于第二部分,它说另一种方法是再次调用该函数,我认为没有人打算这样做。相反,您会这样做x = processorItensiveFunction(); if(x) { alert(x); }
maksim 2014年

8
@maksim:我喜欢可读的代码,但这并不一定意味着代码应该精简或过于冗长。将内容散布在多行上并在变量之间弄乱值实际上会导致代码变差。插入的代码会在弱类型/灵活的语言(例如JS)中产生无法预料的副作用。条件语句中的赋值在javascript中有效,因为您只是问“赋值是否有效,请执行可能包含赋值结果的操作”。但是确实,在条件之前分配也是有效的,不是很冗长,更常用。
okdewit

1
@maksim为什么您认为if ( ! x = anyFunction() )不可读?它不需要任何评论。
JDrake

如果您修复OPC,与其他技能水平不同的开发人员(换句话说,您是专业人士)一起工作,您将讨厌这样做。
davidjmcclelland

2
@maksim-同样,您的解决方案在某种if-else情况下也会非常不便。考虑- 如果最初是正确的,那么if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} 您的先前工作x = processorIntensiveFunction();将被浪费condition
Adrian Bartholomew

16

我做了很多次。为了绕过JavaScript警告,我添加了两个括号:

if ((result = get_something())) { }

您应该避免使用它,如果您真的想使用它,请在它上面写一个注释,说明您在做什么。


1
@SHiNKiROU:如何查看javascript警告?是否有Javascript编译器?还是翻译会产生某种警告?我一直在使用javascript调试中的Firefox控制台,但是从没有看到任何类似的输出。对不起,我的经验有限。
Michael Mao,2010年

5
@Michael:JSLint(jslint.com)是一个流行的程序/库,用于检查JavaScript程序是否存在错误或错误代码。
马修·克鲁姆利

将Mozilla Firefox与Firebug和/或Web Developer扩展配合使用以检查警告。
Ming-Tang 2010年

我只是if ((a = [1, 2]).length > 0) { console.log(a); }a尚未初始化的地方尝试过它,并且确实可以工作(很好!使使用正则表达式更加容易)。我不需要var|const|let这里的任何内容,这是正确的吗?您是否知道我在哪里可以阅读有关此技巧的更多信息?
t3chb0t

4

您也可以在Java中执行此操作。不,这不是一个好习惯。:)

(并使用===Javascript中的类型相等性。请阅读Crockford的JS的The Good Parts书。)


@quixoto:我可以在Java中做这个技巧吗?我想知道...我没有自动atm的jdk,所以我无法获得Java中的示例代码。从我可怜的记忆中,如果返回值评估的不是条件条件语句中的布尔值,Java只会给您一个Runtime错误。
迈克尔·毛

1
嗯,是的,在Java中将其类型检查为布尔类型。但是你可以做的if (foo = getSomeBoolValue()) { }
本·Zotto

是的,没错。一个布尔变量,用于测试是否成功完成操作,另一个变量用于存储返回的值。这就是Java的工作方式,我对此太熟悉了,因此我感到奇怪的是,看到Javascript可以在一行内完成两件事:)
Michael Mao,2010年

@BenZotto为什么不好呢?“为避免意外滥用变量,通常最好将变量引入尽可能小的范围。特别是,通常最好将变量的定义推迟到可以给它赋初始值为止。这两个原则最完美的应用之一是在条件中声明变量。” -Stroustrup,“ C ++编程语言”。
JDrake

1
嗨,我以node.js javascript用户的身份来到这里。为什么在一个我痛苦的情况下没有好的实践:if(myvar ='只是一个测试')创建一个node.js GLOBAL变量myvar(nodejs.org/docs/latest-v12.x/​​api/globals.html #globals_global)。因此,如果您像我一样,并在服务器请求处理中使用了该变量(几秒钟后又有其他请求插入并重新填充该变量),您可能会对获得的结果感到惊讶。因此,建议是:请注意,此模式会在node.js中创建一个全局变量。
pein-consulting.de

4

使用while-loops 时,只有一种情况。
读取文件时,通常会这样:

void readFile(String pathToFile) {
    // Create a FileInputStream object
    FileInputStream fileIn = null;
    try {
        // Create the FileInputStream
        fileIn = new FileInputStream(pathToFile);
        // Create a variable to store the current line's text in
        String currentLine;
        // While the file has lines left, read the next line,
        // store it in the variable and do whatever is in the loop
        while((currentLine = in.readLine()) != null) {
            // Print out the current line in the console
            // (you can do whatever you want with the line. this is just an example)
            System.out.println(currentLine);
        }
    } catch(IOException e) {
        // Handle exception
    } finally {
        try {
            // Close the FileInputStream
            fileIn.close();
        } catch(IOException e) {
            // Handle exception
        }
    }
}

查看while第9行的-loop。在那里,读取新行并将其存储在变量中,然后运行循环的内容。我知道这不是if -statement,但是我想您的问题中也可以包含while循环。

这样做的原因是FileInputStream,每次使用时,每次调用时FileInputStream.readLine(),它都会读取文件的下一行,因此,如果您fileIn.readLine() != null不指定变量就直接从循环中调用它,而不是调用(currentLine = fileIn.readLine()) != null它,则可以,然后从中调用它。在循环内部,您也只会得到第二行。

希望你能理解,祝你好运!


3

您也可以在Java中的if语句中进行赋值。一个很好的例子是读一些东西然后写出来:

http://www.exampledepot.com/egs/java.io/CopyFile.html?l=new

代码:

// Copies src file to dst file.
// If the dst file does not exist, it is created
void copy(File src, File dst) throws IOException 
{
    InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dst);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }
    in.close();
    out.close();
}

@Nitrodist:感谢您的示例。我真的不是Java或javascript专业人士...很高兴知道这种方法在Java中也是可行的:)
Michael Mao,2010年

我不明白这一点。您可以使用Java,PHP和许多其他语言来实现。问题是关于Javascript。
pmrotule '16

不,不一定,您需要仔细阅读问题。
Nitrodist '16

3

如果您要参考Martin Fowlers的《重构改进现有代码的设计》一书!然后,在某些情况下,这将是一个很好的做法,例如 长的复杂条件,使用函数或方法调用来断言您的情况:

“动机

程序中最常见的复杂性领域之一是复杂的条件逻辑。当您编写代码以测试条件并根据各种条件执行各种操作时,很快就会遇到很长的方法。方法的长度本身就是使其难以阅读的一个因素,但是条件会增加难度。问题通常在于这样一个事实,即条件检查和操作中的代码都告诉您发生了什么,但是很容易掩盖其发生的原因。

与任何大的代码块一样,您可以通过分解意图并将代码块替换为以该代码块的意图命名的方法调用来使意图更清晰。>在有条件的情况下,您可以通过对有条件部分和每个替代方案进行操作而获得更多收益。这样,您可以突出显示条件,并清楚地表明您正在分支的内容。您还强调了分支的原因。”

是的,他的答案对于Java实现也是有效的。尽管在示例中,它并未将条件函数分配给变量。


1

这不是一个好习惯。您很快会对此感到困惑。它看起来与一个常见错误类似:滥用“ =”和“ ==”运算符。

您应该将其分成2行代码。它不仅有助于使代码更清晰,而且将来也易于重构。假设您更改了IF条件?您可能会意外删除该行,并且变量不再获得为其分配的值。


@thethanghn:那正是我所担心的。当我变老并且懒惰时,如果只需要较少的击键就够了,我只是不想在代码中键入更多内容:)
Michael Mao 2010年

1
不,我不会感到困惑,我一直都这样做。有好处。
JDrake

但这确实取决于,不是吗?如果您来自“ C”背景(以及其他基于C的语言),则该结构非常熟悉,替代方法也很尴尬。海事组织,这是一次又一次的学习。这不是您会多次绊倒的事情。
马克斯·沃特曼

0

我认为这更像是老式的C风格。在JavaScript中,这并不是真正的好习惯,因此您应该避免使用它。


8
我也不认为这是C语言中的好习惯。
马修·克鲁姆利

1
我确实认为这是许多语言的好习惯。
JDrake

imo,只说“不好的做法”是不够的。它实际上只是关于教育-它是一次学习的,仅此而已。
马克斯·沃特曼


0

我是从golang来到这里的,通常会看到类似

if (err := doSomething(); err != nil) {
    return nil, err
}

其中仅限err于该if块。因此,这就是我在es6中所做的事情,这看起来很丑陋,但是并没有使我相当严格的sslint规则发生变化,并且达到了同样的效果。

{
  const err = doSomething()
  if (err != null) {
    return (null, err)
  }
}

多余的花括号定义了一个新的“词汇范围”吗?这意味着我可以使用const,而err外部块不可用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.