Specific case of using logical vs ternary operators in JavaScript - javascript

I came across this expression in Angular documentation:
(name && name.trim()) || '<no name set>';
This is basically the same as
name ? name.trim() : '<no name set>';
I've tested this for the following inputs for name and both expression result in same:
function fn1(name){
return (name && name.trim()) || '<no name set>';
}
function fn2(name){
return name ? name.trim() : '<no name set>';
}
var inputs = [undefined, null, '','astring']
console.log(inputs.map(fn1));
console.log(inputs.map(fn2));
So the question using which one of the above is a better practice. I guess the ternary one is more readable. However, I appreciate your thoughts about this or anything that I might have missed.
UPDATE
I missed one test, which is an all white-space string. This results in different outputs.
function fn1(name){
return (name && name.trim()) || '<no name set>';
}
function fn2(name){
return name ? name.trim() : '<no name set>';
}
var inputs = [' ','\t']
console.log(inputs.map(fn1));
console.log(inputs.map(fn2));
As suggested by #T.J. Crowder this question can be framed in a less-opinion based form like:
Will (x && x.y) || z ever give a different result from x ? x.y : z?
But what I learned from this framing is more important. When you see a code like one in Angular doc, if you think of it in terms of something more general like above, you can see the difference better. Looking at the new question, it's easy that you see x.y might evaluate to false just like x. And because all values that evaluate to false are not the same because we have empty strings, undefined, etc., then the two expressions are not equal.

Related

sonarlint JavaScript warning: "Remove the unnecessary boolean literal"

Please note: as far as I'm aware this isn't a duplicate. There is some discussion about this warning in other languages but as we all know, == in JavaScript isn't like other languages.
The code reads:
let channelValue = filter == true ? 2 : 1;
SonarLint suggests "remove the unnecessary boolean literal, which tempts me to write:
let channelValue = filter ? 2 : 1;
but of course that will give a different result if filter has the value 87 or "Cheese on Toast". Is there a way to avoid the == true but retain the same semantics?
You should consider using === instead of == as the second one is not recommended and may behave unexpectedly. It also resolves sonarlint warning.
So you code should look like this:
let channelValue = filter === true ? 2 : 1;

Error: Objects are not valid as a React child (found: object with keys {zip})

I get this error when using this code:
const App = () => {
const user = {name: "ff", address: {zip: "Henry street"}};
const zip = user ? user.address: undefined ? user.address.zip : undefined;
return (
<div className="App">
<div>bnm {zip}</div>
</div>
);
}
When I output the zip variable it shows this: {zip: "Henry street"}
This error goes away and it prints out the proper thing when I do this:
const zip = (user ? user.address: undefined) ? user.address.zip : undefined;
Does anybody know why it doesn't work without the parentheses?
Does anybody know why it doesn't work without the parentheses?
Because of operator associativity. The conditional operator has right-to-left associativity. You can think of this as if the operator is trying to find the longest valid expression after the colon and uses that as the alternative value.
Thus your expression is evaluated as
user ? user.address : (undefined ? user.address.zip : undefined)
I.e. if user is "truthy", user.address is returned, which is the object mentioned in the error.
The precedence/associativity is not always obvious or well known, therefore its useful to add parenthesis to make the order of evaluation clearer even if doesn't change it.
There are clearer and less error prone ways to express the same logic:
You can use the optional chaining operator:
const zip = user?.address?.zip;
Or you can use a plain old if statement:
let zip;
if (user && user.address) {
zip = user.address.zip;
}

Array push with ternary operator

I want to push an error message to a field if it is invalid.
this code works
let message = [];
if (!isvalid) {
message.push("Please enter a value");
}
How can I achieve this with ternary operator.
The way I did.
message.push((!isvalid) ? "Please enter a value" : null)
But this code is also pushing null to the array.
like:: message=[null]
Honestly, it's not a good way to do it. It does not make sense to use a ternary where one logical branch of the condition leads to ...do nothing. Ternary only makes sense where you want to return one of two values depending on the condition.
If you want to be concise you could use:
!isValid && message.push('foo');
though some linters won't like you for it. It has the disadvantage that it is less readable than a simple if. If you must use the ternary, you could also do this:
!isValid ? message.push('Please enter a value') : void 0; // or null
but it's ugly and bad because of that useless hanging false branch of the ternary expression. Don't do it.
Can you try (!isvalid) ? message.push("Please enter a value") : null ?

Curious how others would create a fallback for this: som var = number 0 || false?

so, I came across a bug and thought it was interesting. Once I sat and thought about it for 5 seconds, it made sense but curious how one would get past it in the future.
so, I have some hashes set up in an obj. (snippet of code from a larger obj).
someBigObj : {
someObj : {
item1 : 0
item2: 1
item4: 2
item3: 3
}
}
So, I set it up this way because I need to reference an Array position that corresponds to data that is associated with those items.
So, if I happen to reference item1 -- look what we get.
var varReference = someBigObj.someObj['item1'] || false;
// which is equivalent to
var varReference = 0 || false;
see what happens there? that reference is 0. So varReference is always false. I actually want the number 0 in this case because I need to access an array element. I think stringing it is odd to me, because it is not a string, but rather an integer. How can I still use this fallback of || false, but actually get the number 0 to be seen as a valid value.
Note: I understand I can explicitly test etc.. just curious if there is a a shortcut or native js (that I am unaware of) that solves my solutions. figured something like would work but didn't.
Number(0) || false
additional note: I ended not putting a || false, as even if it it's not referenced correctly there is no error. So it doesn't actually matter, but I always like to have fallbacks so that is why I am curious.
If you want falsey values to pass your test, then the test probably needs to look explicitly for undefined, not just a falsey value.
var varReference = someBigObj.someObj['item1'] !== undefined ? someBigObj.someObj['item1'] : false;
Keep in mind that lots of legitimate values are falsey such as 0, "", null (and others).
You can use an inline if to check if your value is undefined explicity.
var varReference = (typeof(someBigObj.someObj['item1']) !== 'undefined') ? someBigObj.someObj['item1'] : false;
Instead of trying to look at the value in the property (and its falsiness, which fails you sometimes), you should check whether the property exists in the object with the in operator:
var varReference = 'item1' in someBigObj.someObj
? someBigObj.someObj['item1']
: false;
which can be simplified to
var varReference = 'item1' in someBigObj.someObj && someBigObj.someObj['item1'];

JavaScript Short Circuit Logic

After seeing some examples online, I've collected two different explanations:
Ex: var x = A || B;
If A exists and B does not, left side is returned.
If A exists and B exists , return right side (last evaluated value).
Based on that logic, I would assume that x would return: v.item(0).click(). But when testing it x first returned B then A, aka fired B then fired A as well. Why? (http://jsfiddle.net/nysteve/QHumL/59/)
HTML:
<div class="indeed-apply-button" onclick="alert('BOOM BUTTON');">boo</div>
<div class='view_job_link' onclick="alert('BOOM LINK');">boo</div>
JavaScript
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
var x = v.item(0).click() || i.item(0).click();
EDIT 1:02 PM 10/10/2013
Did not mention my true intentions, but based on the answer and discussion, my goal was essentially to convert the following piece of code into the JavaScript code I originally mentioned.
var v = document.getElementsByClassName('view_job_link');
var i = document.getElementsByClassName('indeed-apply-button');
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
In the code above, how would you read if(v){v.item(0).click();} vs. the short-circuit?
Neither of your two descriptions are accurate.
var x = A || B;
What that does is:
Evaluate "A". Call the result VA.
If VA is not null, undefined, 0, NaN, false, or the empty string, then the value of the overall expression is VA and evaluation stops.
Evaluate "B". Call the result VB. That value, VB, is the value of the expression.
Your test code first tests the return value of calling the "click" function on the first element and then the second. Those functions both return undefined, so the subexpressions on both sides of the || are evaluated. That is, the first call gets VA and it's undefined, so that means that the other side will be evaluated too, and that'll be the value of the expression. (It's going to come out undefined.)
edit — OK now that you've added more to the answer, I think I see what you're up to.
In your actual code (or, I guess, the sample code that's closer to reality), you've got:
if(v){v.item(0).click();}
else if(i){i.item(0).click();}
else{}
That means something quite different than:
var x = v.item(0).click() || i.item(0).click();
Note that in the if statement version, it's explicitly checking "v". A test like that will perform a "truthy/falsy" test on the value of "v". In this case, it's really checking to make sure that "v" isn't either null or undefined. In the || version, however, there's no such explicit test for the "goodness" of variable "v"; it's just used directly. (If it happens to be null there, that'd result in a runtime error.)
A version of the actual code using || and && is possible, but in my opinion the existing code is clearer. However, just for discussion purposes, you could replace the if version with:
v && (v.item(0).click(), true) || i && i.item(0).click();
Personally I think that looks kind-of ugly.

Categories

Resources