0

I'm trying to understand how the third line in this code snippet (the assignment value = f in the condition of the conditional expression) is working:

someProp(propName, f) {
  let prop = this._props && this._props[propName], value
  if (prop != null && (value = f ? f(prop) : prop)) return value
  ...
}

In this example, value is undefined at the console.log(value) statement:

let f = 42;
value = f ? console.log('true') : console.log('false');
console.log(value);

It seems to me that the value variable returned on the third line of the first snippet would always be undefined. What am I missing? The snippet is from production code in an open source project I'm studying.

Also, this._props is an object. Why is the author using if (prop != null && ... to test if the props object exists, rather than just something like if (prop && ... ? And am I right in thinking that this is typical code of more experienced developers, or would others write it differently?

3
  • 1
    value = f ? console.log('true') : console.log('false'); in this case value will always be undefined because it will be set to the return value of console.log() which is always undefined. value = f ? f(prop) : prop) in this case, if f is falsey, then value = prop, if f`` is truthy (based on context, I suspect a callback), then value` will be what is returned by f(prop) Commented Apr 29, 2018 at 15:59
  • Can you link the full code in the open source project you are studying? Commented Apr 29, 2018 at 16:00
  • @Bergi It's line 179 in this file from the ProseMirror project Commented Apr 29, 2018 at 16:07

3 Answers 3

1

The conditional operator has a higher precedence than the assignment operator, so this is parsed

if (prop != null && (value = (f ? f(prop) : prop))) return value
//                           ^                  ^

not

if (prop != null && ((value = f) ? f(prop) : prop)) return value
//                   ^         ^

as you were expecting. So yes, in your demo example you always get undefined as that's the return value of the console.log calls. But here it is assigned either f(prop) or prop.

Also, why is the author using prop != null && ... rather than just prop && ...?

Because he likes being explicit.

And am I right in thinking that this is typical code of more experienced developers?

No. Possibly typical code of developers that were once bitten by falsy values.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your help, Bergi. I sincerely appreciate it. Am I correct in thinking it would be easy to trip on writing code like this myself, relying on operator precedence? Or is it pretty normal? I'm trying to improve my skills.
In general, yes it's pretty normal to rely on operator precedence - we do it every day when writing stuff like 1 + 2 * 3. Admittedly, this one is a bit extreme (the whole function in the project you linked is, uh, dense), so just write explicit grouping operators when you are not sure. You will get more familiar with the precedence rules over time.
1

Let's examine this line:

if (prop != null && (value = f ? f(prop) : prop)) return value

Especially this part:

(value = f ? f(prop) : prop) 

If f is truthy, set value to the return value of f(prop).

If f is not thruthy, set value to the value of prop.

Value is then checked for thruthyness and returned.


In your second example:

let f = 42;
value = f ? console.log('true') : console.log('false');
console.log(value);

What you are actually doing is setting value to the return value of console.log('true') which is always going to be undefined, since console.log() returns undefined.


And am I right in thinking that this is typical code of more experienced developers, or would others write it differently?

For easier understanding, and especially if the code is used in tutorials, I would personally expand the code for better readability among learners, but I also like my code compact, so if it was code for a library, I'd probably code along those lines too.

1 Comment

Thanks Luca, esp. for the comment on style
1

Personally I think this is badly written; experience aside, it's too hard to read. Ternary inside an if condition which does an assignment which then may get returned - calm down.

Here it is longhand:

if ( prop != null ) {
    if ( f ) {
        value = f( prop );
    } else {
        value = prop;
    }
    if ( value ) return value;
}

An extra quirk is that value won't be returned if it's falsy, which (I guess) is why its assignment was part of the if condition. It is clever of the author to cram all this logic into one line but in my opinion it's better dumbed down.

4 Comments

no, the original code checks value with assigned value as well.
@NinaScholz could you explain that comment a little more? I'm having trouble understanding it.
you return the value of f(prop), and omit the check of && (value = f ? f(prop) : prop), where the value is checked and if not truthy, no return takes place.
@NinaScholz Yeah I missed that

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.