154

I moved one years ago from classic OO languages such like Java to JavaScript. The following code is definitely not recommended (or even not correct) in 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));
    }
    return false;
}

Basically I just found out that I can assign a variable to a value in an if condition statement, and immediately check the assigned value as if it is boolean.

For a safer bet, I usually separate that into two lines of code, assign first then check the variable, but now that I found this, I am just wondering whether is it good practice or not in the eyes of experienced JavaScript developers?

Carson
  • 6,105
  • 2
  • 37
  • 45
Michael Mao
  • 9,878
  • 23
  • 75
  • 91
  • `"The following code is definitely not recommended (or event not correct) in Java..."` Is it even correct in JavaScript? Because, as far as I can see, you return an integer (`return parseInt(...)`) if `dayNumber != -1` is true, but a boolean if it is false. – Daniel Kvist Jul 03 '15 at 10:35

10 Answers10

162

I wouldn't recommend it. The problem is, it looks like a common error where you try to compare values, but use a single = instead of == or ===. For example, when you see this:

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

you don't know if that's what they meant to do, or if they intended to write this:

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

If you really want to do the assignment in place, I would recommend doing an explicit comparison as well:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}
Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • 2
    @Matthew Crumley : this answers my question in a clear way. I am not checking by assigning but checking whatever the value evaluates to be after the assignment. Is this understanding right? – Michael Mao Apr 05 '10 at 02:10
  • 2
    @Michael: yes, that's correct. Adding the comparison basically just makes your intentions more clear. – Matthew Crumley Apr 05 '10 at 02:13
  • 5
    The last example doesn't work, however, if you're testing for fail/success of a function that returns a boolean. In other words, while `if (resultArr = myNeedle.exec(myHaystack)) {...}` works, `if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}` does not because the assignment to resultArr is always truthy even when the function result is not. If anyone uses this.. construct, remember to declare the result variable first; 'var' is not legal within the if condition statement. – Ville Apr 15 '13 at 22:10
  • 3
    You can use `if (!!(value = someFunction()))`, but as you said, the problem is that you can't use `var` inside `if` so you either end up creating a global, or achieve nothing as you have to declare `value` in a separate line anyway. Shame, I really liked this construction in C++. – riv Mar 30 '15 at 17:05
  • @Ville I'm not seeing the problem with functions that return booleans. `(x = f()) === false` evaluates to true if `f()` returns `false`. Am I misunderstanding what you were trying to say? – Anthony Grist Sep 09 '15 at 08:12
  • 1
    @riv, you're right; in case the function returns a boolean – like I said in my above comment – then the conditional works as expected. But if the function returns a boolean (as in my example) then the whole construct is kind of non-sensical; clearly my line of thinking was – judging from the example – that the function would return an array. A quick test indicates that the condition evaluates to `true` only when the function returns `true`, but in all other cases (including when an array, string, number, or null is returned) it evaluates to `false`. – Ville Sep 10 '15 at 04:06
  • (I mean @Anthony Grist, not riv, sorry for the mix-up.. couldn't edit my comment anymore :-]). – Ville Sep 13 '15 at 05:06
  • In the third example, this is a common pattern I saw in Symfony 1.x and I thought it was weird but this makes the assignment more obvious:`if (false === ($result = mySqlSomething($query))` –  Dec 31 '16 at 11:45
  • What is the context of `value` in this case. I don't see any leading `let` or `var`. – nowox Aug 16 '18 at 20:07
39

I see no proof that it is not good practice. Yes, it may look like a mistake but that is easily remedied by judicious commenting. Take for instance:

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

Why should that function be allowed to run a 2nd time with:

alert(processorIntensiveFunction());

Because the first version LOOKS bad? I cannot agree with that logic.

borisdiakur
  • 10,387
  • 7
  • 68
  • 100
Adrian Bartholomew
  • 2,506
  • 6
  • 29
  • 37
  • 53
    Not to dig up an old comment, but I don't agree with your arguments. Readable code should explain itself without the need for a comment - adding a comment to confusing code isn't a remedy. As for the second part, which says the alternative is to call the function again, I don't think anyone intends to do that. Instead you would do `x = processorItensiveFunction(); if(x) { alert(x); }` – maksim Dec 25 '14 at 23:34
  • 12
    @maksim: I like readable code, but that doesn't necessarily mean code should be dumbed down or too verbose. Spreading things over multiple lines and juggling values between variables can actually lead to worse code. Inserted code can have unforeseen side effects in a weakly typed / flexible language like JS. Assignment in a conditional statement is valid in javascript, because your just asking "if assignment is valid, do something which possibly includes the result of the assignment". But indeed, assigning before the conditional is also valid, not too verbose, and more commonly used. – okdewit Jul 15 '15 at 11:30
  • 1
    @maksim why would you think `if ( ! x = anyFunction() )` is not readable? It doesn't need any comments whatsoever. – jdrake Jun 08 '17 at 10:08
  • If you fix OPC, work with other devs of varying skill levels (in other words, you are a professional) you will hate that this is even possible. – davidjmcclelland Oct 17 '17 at 19:32
  • @maksim: If you follow best practices and use `===` instead of `==` always, then the intended and visual difference between `===` and `=` is quite profound. – Adrian Bartholomew May 02 '19 at 18:47
  • 3
    @maksim - also your solution would be very inconvenient in an `if-else` situation. Consider- `if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)}` Your prior `x = processorIntensiveFunction();` would be a wasted effort should the initial `condition` be true. – Adrian Bartholomew Jun 03 '19 at 01:03
  • Agree with @AdrianBartholomew. I think it's fine.@matthew-crumley's point notwithstanding, this is a valid language construct, which when judiciously applied can make code more concise and I'd argue clear. In my experience, ambiguity among readers generally (not always) relates a misunderstanding of how assignment with-in a conditional statement works. Once clear on the behavior, they can view and employ this approach with no issue. – Adam Jun 18 '19 at 13:03
21

I did it many times. To bypass the JavaScript warning, I add two parens:

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

You should avoid it, if you really want to use it, write a comment above it saying what you are doing.

Ming-Tang
  • 17,410
  • 8
  • 38
  • 76
  • 2
    @SHiNKiROU : how can I see javascript warnings? Is there a Javascript compiler? or the interpreter will generate some sort of warning? I am using Firefox console as in javascript debugging all the time but never see any similar outputs. Sorry about my limited experience. – Michael Mao Apr 05 '10 at 01:57
  • 6
    @Michael: JSLint (http://www.jslint.com/) is a popular program/library that checks JavaScript programs for possible mistakes or bad code. – Matthew Crumley Apr 05 '10 at 02:44
  • Use Mozilla Firefox with Firebug and/or Web Developer extension to check warnings. – Ming-Tang Apr 05 '10 at 03:33
  • 1
    I just tried it with `if ((a = [1, 2]).length > 0) { console.log(a); }` where `a` isn't initialized anywhere yet and it indeed worked (nice! makes using regex much easier). Is this correct that I don't need any of `var|const|let` here? Do you happen to know where I could read more about this _trick_? – t3chb0t Oct 27 '19 at 11:16
  • 1
    @t3chb0t: As of 2022, in JavaScript, the [= assignment](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-assignment-operators) without var|let|const is an _expression_. That means, it can be used anywhere expressions can be used, including within an `if(...)`. Also note, that unless the variable `a` has been declared earlier, it will be **global**. This is usually not what you want. – Michael Sep 05 '22 at 14:04
9

There is one case when you do it, with while-loops.
When reading files, you usualy do like this:

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
        }
    }
}

Look at the while-loop at line 9. There, a new line is read and stored in a variable, and then the content of the loop is ran. I know this isn't an if-statement, but I guess a while loop can be included in your question as well.

The reason to this is that when using a FileInputStream, every time you call FileInputStream.readLine(), it reads the next line in the file, so if you would have called it from the loop with just fileIn.readLine() != null without assigning the variable, instead of calling (currentLine = fileIn.readLine()) != null, and then called it from inside of the loop too, you would only get every second line.

Hope you understand, and good luck!

user229044
  • 232,980
  • 40
  • 330
  • 338
Daniel Kvist
  • 3,032
  • 5
  • 26
  • 51
6

If you were to refer to Martin Fowlers book Refactoring improving the design of existing code ! Then there are several cases where it would be good practice eg. long complex conditionals to use a function or method call to assert your case:

"Motivation

One of the most common areas of complexity in a program lies in complex conditional logic. As you write code to test conditions and to do various things depending on various conditions, you quickly end up with a pretty long method. Length of a method is in itself a factor that makes it harder to read, but conditions increase the difficulty. The problem usually lies in the fact that the code, both in the condition checks and in the actions, tells you what happens but can easily obscure why it happens.

As with any large block of code, you can make your intention clearer by decomposing it and replacing chunks of code with a method call named after the intention of that block of code. > With conditions you can receive further benefit by doing this for the conditional part and each of the alternatives. This way you highlight the condition and make it clearly what you > are branching on. You also highlight the reason for the branching."

And yes his answer is also valid for Java implementations. It does not assign the conditional function to a variable though in the examples.

Community
  • 1
  • 1
allan
  • 61
  • 1
  • 4
  • This seems to be about using functions/methods, especially when also using conditionals. This does not address the question. – Akaisteph7 May 11 '23 at 15:41
4

I came here from golang, where it's common to see something like

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

In which err is scoped to that if block only. As such, here's what I'm doing in es6, which seems pretty ugly, but doesn't make my rather strict eslint rules whinge, and achieves the same.

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

The extra braces define a new, uh, "lexical scope"? Which means I can use const, and err isn't available to the outer block.

Adam Barnes
  • 2,922
  • 21
  • 27
3

You can do this in Java too. And no, it's not a good practice. :)

(And use the === in Javascript for typed equality. Read Crockford's The Good Parts book on JS.)

Ben Zotto
  • 70,108
  • 23
  • 141
  • 204
  • 1
    @quixoto : Could I do this trick in Java? I wonder... I don't have jdk by hand atm so I am unable to get a sample code in Java. From my poor memory, Java will just get you a Runtime error if the returning value evaluates something not boolean as in if conditional statement, right? – Michael Mao Apr 05 '10 at 01:52
  • 2
    Ah, yes, in Java it's type-checked to be a boolean type. But you *can* do `if (foo = getSomeBoolValue()) { }` – Ben Zotto Apr 05 '10 at 01:57
  • 1
    yeah that's right. a boolean variable to test whether something succeeded and another variable to store the value returned. That's how Java does its job, I am too familiar with that so I feel strange to see Javascript can do two things in one mere line :) – Michael Mao Apr 05 '10 at 02:00
  • @BenZotto it's not good practice why? "To avoid accidental misuse of a variable, it is usually a good idea to introduce the variable into the smallest scope possible. In particular, it is usually best to delay the definition of a variable until one can give it an initial value ... One of the most elegant applications of these two principles is to declare a variable in a conditional." -- Stroustrup, "The C++ Programming Language." – jdrake Jun 08 '17 at 10:12
  • @JDrake I believe Stroustrup's example shows an explicit typed declaration inside the conditional and the elegance he refers to relies on C++'s block scope, which JS doesn't have (without using the `let` keyword anyway). But in any case, the accepted answer on this question lays out the semantic ambiguity most people like to avoid for clarity across lots of C-like languages. – Ben Zotto Jun 08 '17 at 19:57
  • Sure most people can do that. But stating that we should avoid it, is a matter of taste. There is absolutely no reason why we should avoid: `if ( ! x = anyFunction() )` . I ask again, why "it's not a good practice" ? – jdrake Jun 08 '17 at 20:36
  • @JDrake: It turns out nearly everything is a matter of taste. The downsides of this practice are clearly laid out here and elsewhere. You may write your conditionals in whatever way you find preferable. – Ben Zotto Jun 08 '17 at 22:12
  • 2
    Hi, I came here as node.js javascript user. Why there it's not good practice in one case I had pain with: if (myvar = 'just a test') Creates a node.js GLOBAL variable myvar (https://nodejs.org/docs/latest-v12.x/api/globals.html#globals_global). So if you're like me and used that variable in server request handling (coming back to it after a few seconds when other requests might have dropped in and stuff), you can be surprised at what results you get. So the recommendation is: Be aware that this pattern creates a global variable in node.js. – tinkering.online May 02 '20 at 12:01
3

You can do assignments within if statements in Java as well. A good example would be reading something in and writing it out:

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

The code:

// 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
  • 1,585
  • 5
  • 24
  • 34
  • @Nitrodist : thanks for this example. I am really not pro in either Java or javascript... It is good to know this approach is also feasible in Java :) – Michael Mao Apr 05 '10 at 10:46
  • 1
    I don't see the point of this. You can do it in Java, PHP and many other languages. The question was about Javascript. – pmrotule Nov 24 '16 at 10:55
  • No it isn't necessarily, you need to re-read the question carefully. – Nitrodist Dec 01 '16 at 21:14
0

It's not good practice. You soon will get confused about it. It looks similiar to a common error: misuse "=" and "==" operators.

You should break it into 2 lines of codes. It not only helps to make the code clearer, but also easy to refactor in the future. Imagine that you change the IF condition? You may accidently remove the line and your variable no longer get the value assigned to it.

thethanghn
  • 319
  • 2
  • 5
  • 21
  • @thethanghn: that exactly what I am afraid of. when I get older and lazy I just don't want to type more into the code if fewer keystrokes will just suffice :) – Michael Mao Apr 05 '10 at 02:37
  • 2
    No, I don't get confused and I do it all the time. There are benefits to it. – jdrake Jun 08 '17 at 10:12
  • It really depends, though, doesn't it? If you come from a 'C' background (and other languages based on C), then the construct is very familiar, and the alternatives are very awkward. IMO, it is something that is learned once and then you know. It's not something you will trip over more than once. – Max Waterman Jun 10 '20 at 01:33
0

you could do something like so:

if (value = /* sic */ some_function()){
  use_value(value)
}
Joseph Le Brech
  • 6,541
  • 11
  • 49
  • 84