How to write a ternary operator (aka if) expressio

2020-02-17 08:12发布

For example, something like this:

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0

Is there a better way to write that? Again, I am not seeking an answer to the exact question above, just an example of when you might have repeated operands in ternary operator expressions...

17条回答
姐就是有狂的资本
2楼-- · 2020-02-17 08:51

Code should be readable, so being succinct should not mean being terse whatever the cost - for that you should repost to https://codegolf.stackexchange.com/ - so instead I would recommend using a second local variable named index to maximize reading comprehensibility (with minimal runtime cost too, I note):

var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;

But if you really want to cut this expression down, because you're a cruel sadist to your coworkers or project collaborators, then here are 4 approaches you could use:

1: Temporary variable in a var statement

You can use the var statement's ability to define (and assign) a second temporary variable index when separated with commas:

var index = someArray.indexOf(3), value = index !== -1 ? index: 0;

2: Self-executing anonymous function

Another option is an self-executing anonymous function:

// Traditional syntax:
var value = function( x ) { return x !== -1 ? x : 0 }( someArray.indexOf(3) );

// ES6 syntax:
var value = ( x => x !== -1 ? x : 0 )( someArray.indexOf(3) );

3: Comma operator

There is also the infamous "comma operator" which JavaScript supports, which is also present in C and C++.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

You can use the comma operator when you want to include multiple expressions in a location that requires a single expression.

You can use it to introduce side-effects, in this case by reassigning to value:

var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );

This works because var value is interpreted first (as it's a statement), and then the left-most, inner-most value assignment, and then the right-hand of the comma operator, and then the ternary operator - all legal JavaScript.

4: Re-assign in a subexpression

Commentator @IllusiveBrian pointed out that the use of the comma-operator (in the previous example) is unneeded if the assignment to value is used as a parenthesized subexpression:

var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );

Note that the use of negatives in logical expressions can be harder for humans to follow - so all of the above examples can be simplified for reading by changing idx !== -1 ? x : y to idx == -1 ? y : x:

var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );
查看更多
欢心
3楼-- · 2020-02-17 08:52

I like @slebetman's answer. The comment under it express concern about the variable being in an "intermediate state". if this is a big concern for you then I suggest encapsulating it in a function:

function get_value(arr) {
   var value = arr.indexOf(3);
   if (value === -1) {
     value = 0;
   }
   return value;
}

Then just call

var value = get_value( someArray );

You could do more generic functions if you have uses for them in other places, but don't over-engineer if it's a very specific case.

But to be honest I would just do as @slebetman unless I needed to re-use from several places.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2020-02-17 08:52

There are two ways I can see of looking at your question: you either want to reduce line length, or you specifically want to avoid repeating a variable in a ternary. The first is trivial (and many other users have posted examples):

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;

can be (and should be, given the function calls) shortened like so:

var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;

If you are looking for a more generic solution that prevents the repetition of a variable in a ternary, like so:

var value = conditionalTest(foo) ? foo : bar;

where foo only appears once. Discarding solutions of the form:

var cad = foo;
var value = conditionalTest(foo) ? cad : bar;

as technically correct but missing the point, then you are out of luck. There are operators, functions, and methods that possesses the terse syntax you seek, but such constructs, by definition, aren't ternary operators.

Examples:

javascript, using || to return the RHS when the LHS is falsey:

var value = foo || bar; // equivalent to !foo ? bar : foo
查看更多
劫难
5楼-- · 2020-02-17 08:52

Given the example code at Question it is not clear how it would be determined that 3 is or is not set at index 0 of someArray. -1 returned from .indexOf() would be valuable in this instance, for the purpose of excluding a presumed non-match which could be a match.

If 3 is not included in array, -1 will be returned. We can add 1 to result of .indexOf() to evaluate as false for result being -1, where followed by || OR operator and 0. When value is referenced, subtract 1 to get index of element of array or -1.

Which leads back to simply using .indexOf() and checking for -1 at an if condition. Or, defining value as undefined to avoid possible confusion as to actual result of evaluated condition relating to original reference.

var someArray = [1,2,3];
var value = someArray.indexOf(3) + 1 || 1;
console.log(value -= 1);

var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || 1;
// how do we know that `4` is not at index `0`?
console.log(value -= 1);

var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || void 0;
// we know for certain that `4` is not found in `someArray`
console.log(value, value = value || 0);

查看更多
欢心
6楼-- · 2020-02-17 08:52

For this particular case, you could use short-circuiting with the logical || operator. As 0 is considered falsy, you can +1 to your index, thus, if index+1 is 0 then you'll get the right-hand side of the return as your result, otherwise, you'll get your index+1. You can then -1 from this result to get your index:

const someArray = [1, 2, 3, 4];
const v = ((someArray.indexOf(3)+1) || 1)-1;
console.log(v);

查看更多
霸刀☆藐视天下
7楼-- · 2020-02-17 08:54

EDIT: Here it is, the proposal for Nullary-coalescing now in JavaScript!


Use ||

const result = a ? a : 'fallback value';

is equivalent to

const result = a || 'fallback value';

If casting a to Boolean returns false, result will be assigned 'fallback value', otherwise the value of a.


Be aware of the edge case a === 0, which casts to false and result will (incorrectly) take 'fallback value' . Use tricks like this at your own risk.


PS. Languages such as Swift have nil-coalescing operator (??), which serves similar purpose. For instance, in Swift you would write result = a ?? "fallback value" which is pretty close to JavaScript's const result = a || 'fallback value';

查看更多
登录 后发表回答