Question mark and colon in JavaScript - javascript

I came across the following line
hsb.s = max != 0 ? 255 * delta / max : 0;
What do the ? and : mean in this context?

It is called the Conditional Operator (which is a ternary operator).
It has the form of: condition ? value-if-true : value-if-false
Think of the ? as "then" and : as "else".
Your code is equivalent to
if (max != 0)
hsb.s = 255 * delta / max;
else
hsb.s = 0;

Properly parenthesized for clarity, it is
hsb.s = (max != 0) ? (255 * delta / max) : 0;
meaning return either
255*delta/max if max != 0
0 if max == 0

This is probably a bit clearer when written with brackets as follows:
hsb.s = (max != 0) ? (255 * delta / max) : 0;
What it does is evaluate the part in the first brackets. If the result is true then the part after the ? and before the : is returned. If it is false, then what follows the : is returned.

hsb.s = max != 0 ? 255 * delta / max : 0;
? is a ternary operator. It works like an if in conjunction with the :
!= means not equals
So, the long form of this line would be
if (max != 0) { //if max is not zero
hsb.s = 255 * delta / max;
} else {
hsb.s = 0;
}

?: is a short-hand condition for else {} and if(){} problems.
So your code is interchangeable to this:
if(max != 0){
hsb.s = 225 * delta / max
}
else {
hsb.s = 0
}
MDN - Conditional (Ternary) Operator

? : isn't this the ternary operator?
var x= expression ? true:false

What you are referring to is called a ternary operator, it is essentially a basic if condition check that can be written to execute an operation if the block of code within the ternary operation is valid, otherwise default to a fallback.
A ternary operation is written in the following syntax:
condition ? exprIfTrue : exprIfFalse
condition An expression whose value is used as a condition.
exprIfTrue An expression which is evaluated if the condition evaluates to a truthy value (one which equals or can be converted to true).
exprIfFalse An expression which is executed if the condition is falsy (that is, has a value which can be converted to false).
Example
Take the given function below which should return the string Yes if the number provided to the function is even, otherwise return No.
function isEven(num) {
return (num % 2 == 0) ? "Yes" : "No";
}
console.log("2: " + isEven(2));
console.log("3: " + isEven(3));
Explanation
The operation above broken down:
(num % 2 == 0) | This is a simple if statement condition to check if the expression within the brackets is true.
? "Yes" If the operation is true, the string literal given is automatically returned as a result of this execution.
: "No" This is the else clause in this operation, if the condition is not met then No is returned.

Be careful with this. A -1 evaluates to true although -1 != true and -1 != false. Trust me, I've seen it happen.
so
-1 ? "true side" : "false side"
evaluates to "true side"

Related

Function explanation using the ?: ( conditional operator in javascript )

I'm trying to understand this function that returns the ordinal numbers when we give it a number.
Unfortunately I couldn't figure out how this is working with the conditional operator, could someone explain it to me?
function getOrdinalNum(n) {
return n + (n > 0 ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] : '');
}
The best way to explain this sort of thing is to break it down into a function with if statements. Take a look at the newFunction it does the same thing that the function getOrdinalNum does:
function getOrdinalNum(n) {
return n + (n > 0 ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] : '');
}
function newFunction(n) {
if (n > 0) {
if ((n > 3 && n < 21) || n % 10 > 3) {
return n + 'th'; // essentially returning ['th', 'st', 'nd', 'rd'][0];
} else {
return n + ['th', 'st', 'nd', 'rd'][n % 10];
}
}
}
for(let i = 1; i < 9; i++) {
console.log(getOrdinalNum(i));
console.log(newFunction(i));
}
Break it down like this:
n +
(
n > 0
? ['th', 'st', 'nd', 'rd']
[
(n > 3 && n < 21) || n % 10 > 3
? 0
: n % 10
]
: ''
);
Here:
JS checks if n > 0. If yes then:
An array is created ['th', 'st', 'nd', 'rd']
The next [] tells us a property accessor will follow
Which property is determined by the ternary operation. Either 0 (which will mean (th) or the result of n & 10
And the result of accessing that property is added whatever n was.
If n is smaller or equal with 0 then whatever n was, an empty string is added to it.
It helps to know the operator precedence in JS. Give it a goooood read and practice some.
Operators (unary, binary, ternary)
The ternary conditional operator is different than most other operators in that it takes 3 operands instead of one or two.
You are used to unary operators like the negative symbol in -5 which takes one operand and makes it a negative value.
There is also the binary concatenation operator + used like 'hello ' + 'world'. Here there are two operands which produce the value 'hello world'.
The ternary conditional operator has the form
/* conditional expression */ ? /* expression if truthy */ : /* expression if not truthy*/
Where the comments are the operands for you to fill in with the more complex code from your example. // if n > 0 then the complex expression, otherwise the empty string
Simple example.
Try to run the following statements in your browser.
console.log(true ? 'true value' : 'false value');
var x = 3 > 1 ? 'true value' : 'false value';
console.log(x);
prompt('try entering a blank space, or characters') ? 'a' : 'b';
The code flows much the same as the other answers describe. The first expression is emitted if the condition is truthy otherwise the second expression is emitted.
Here are some docs on what I mean by truthy

Boolean expressions - getting mixed up with AND, OR logical operators and how they work

I have to convert a number to comma format. E.g 12345 => 12,345.
I have my solution :
function convert(n) {
n = n.toString();
var result = '';
var count = 0,
var idx = n.length - 1;
while (r = n[idx]) {
count++;
result = ((count % 3 == 0 && count != n.length) ? ',' : '') + r + result;
idx--;
}
return result;
}
But someone else used :
result = ((count % 3 != 0 || count == n.length) ? '' : ',') + r + result;
They both work but now I am confused about my own solution and just lost why they both work. Ah not sure if my question is clear.
!(x AND y) is equal to !x OR !y
(and you can pull a NOT out of a boolean x by double negation, for example:
x == !!x
so
x AND !y (your original expression) is equivalent to !(!x OR y)
if you remove the negation (!) from the beginning, then you actually get the Negated form and that is why the second and third values of the ternary operator are reversed in your second example.
The two expressions are equivalent, the second one is just the negated version of yours. The opposite (more or less) of == is !=, the opposite of && is ||, and the opposite of true is false.
You are placing a comma whenever the count is divisible by 3 and you aren't at the start of the number. They are not placing a comma anytime the count is not divisible by 3 or they are at the start of the number.
Assume that, count % 3 = 0 and count > n.length
Now your logic:
((count % 3 == 0 && count != n.length) ? ',' : '')
which means True && True which results in True hence the first condition after ? which is "," is selected.
Someone else logic:
((count % 3 != 0 || count == n.length) ? '' : ',')
which means 'False || False' which results in 'False' hence second condition after ? which is "," is selected.
P.S: Both are using similar logic

Need an elegant way to change the return results of a in line if statement based on inputs

To better explain what Im trying to do Im going to preface a bit with no code and then show you the code I am working with in the pertinent pieces.
I currently and working with a function that measures the width and height of a canvas element and divides half of each size by an inputted number. I then decide if the resulting number is even by using math.ceil() and %2===0. Using this formula I will decide if the width is boolean true or false and the same for the height.
In the end I will have
var A = True (or False)
var B = True (or False)
I then have the creation of a 3 dimensional array:
var pax = [];
for (var i = 0; i < stage.height()/12; i++){
pax[i] = [];
for (var j = 0; j < stage.width()/12; j++){
pax[i][j] = [];
pax[i][j].push("if statement here");
};
}
I need an elegant way to replace "if statement here" with something like a double if statement where
if (A === B) {
(((i%2)===0)===((j%2)===0)) ? 0 : 180)
||
(((i%2)===0)!==((j%2)===0)) ? 180 : 0)
} else {
(((i%2)===0)===((j%2)===0)) ? 180 : 0)
||
(((i%2)===0)!==((j%2)===0)) ? 0 : 180)
};
Im pretty sure this monstrosity that I just typed wont work, so I need both the correct way to type the syntax and a more elegant and resource light way to do it, just due to the amount of index locations I will be pushing to in the array.
Basically what Im trying to do is say "Based on the height and width of the canvas, if i is even, return 0, and if i is odd, return 180, OR based on the height and width of the canvas, if i is even, return 180, and if i is odd, return 0.
I can attempt to explain this again if this is unclear.
You want your modulus operations to match or not match. With x % 2, there can only be one of two results, so there's no point in converting to a boolean with ===. And the parens are just excessive. All that clutter doesn't help. So here's a first pass:
if (A === B) {
(i%2===j%2 ? 0 : 180) || (i%2!==j%2 ? 180 : 0)
} else {
(i%2===j%2 ? 180 : 0) || (i%2!==j%2 ? 0 : 180)
}
Then it seems that you want the numbers flipped based on comparison to A === B. So if they are equal and even you want 0, 180 or if they are unequal and odd, you want 180, 0. So basically if the i/j comparison and the A/B comparison are the same, you have one result, otherwise, the other.
The odd thing is that when one % test succeeds but yields 0 the || operation makes it attempt the opposite % test, which of course will fail. But because the numbers are reversed for the second test, we end up with the correct value. It's just that you're going about it in a roundabout way.
Ultimately, what your code does is simply this:
(A === B) === (i%2===j%2) ? 0 : 180
Here's a demo that shows that your original and short version achieve the same result.
DEMO: http://jsfiddle.net/jDWf6/3/
(EDIT: Updated demo to show all values tested.)
The condition:
if (A === B) {
(((i%2)===0)===((j%2)===0)) ? 0 : 180)
||
(((i%2)===0)!==((j%2)===0)) ? 180 : 0)
} else {
(((i%2)===0)===((j%2)===0)) ? 180 : 0)
||
(((i%2)===0)!==((j%2)===0)) ? 0 : 180)
};
(There's no need for a semi–colon after a block statement)
is overly complex and can be reduced to (assuming it should return something):
var result;
if (A === B) {
result = i%2 == j%2? 0 : 180 || i%2 != j%2? 180 : 0;
} else {
result = i%2 == j%2? 180 : 0 || i%2 != j%2? 0 : 180;
}
In the first assignment, the two || operands return the same value for any given values of i and j, so it might as well be:
result = i%2 == j%2? 0 : 180;
since if i%2 == j%2 returns true, then:
i%2 == j%2? 0 : 180
returns 0, which converts to false, so the second expression is evaluated:
i%2 != j%2? 180 : 0
and i%2 != j%2 must return false (since the opposite was true) and again 0 is returned. The exact opposite occurs if the original expression returned false:
i%2 == j%2? 0 : 180
returns 180, which is truthy, so the otehr side of the || is not evaluated.
So now you have:
if (A === B) {
result = i%2 == j%2? 0 : 180;
} else {
result = i%2 == j%2? 180 : 0;
}
That means that the result of:
i%2 == j%2? 0 : 180
is reversed based on A === B, so:
result = A === B? (i%2 == j%2? 0 : 180) : (i%2 == j%2? 180 : 0)
Of course this could be way off if your pseudo code isn't doing what you hoped…
ok my friend based on what you asking here is the answer.
*I don't know if this will be what you will looking for because your logic is a bit complicated and not so correct....
As you can see i reduced the code and i maximized the performance. Also i make clear what "i" is and what "j". Just to be more readable...
var pax = [];
var isHeightEven, isWidthEven;
for (var height = 0; height < stage.height() / 12; height++) {
pax[height] = [];
for (var width = 0; width < stage.width() / 12; width++){
pax[height][width] = [];
isHeightEven = !(height % 2); //calculate only once
isWidthEven = !(width % 2); //calculate only once
pax[height][width].push(
(A === B) ? ((isHeightEven && isWidthEven) ? 0 : 180) : ((isHeightEven && isWidthEven) ? 180 : 0)
);
};
}

Surprising value assignment due to operator precedence?

Original question based on completely wrong logic :O
$(function() {
var x=0,y=1;
$("#div_id").find("input:text").each(function (i, input) {
$(this).val(""+(i % 2 == 0)?x++:y++);
});
});
If I remove the ""+ from the value, I get this wrong result
instead of what I want, which is this:
Same if I use prop:
$(this).prop("value",""+(i % 2 == 0)?x++:y++);
Same if I prefix the ++
What am I overlooking? Is this an obvious thing?
UPDATE: I completely missed the boat here.
Here is the code I meant to write and it works without the ""
$(function() {
var x=0,y=1;
var inputs = $("#div_id").find("input:text");
var y = Math.ceil(inputs.size()/2);
inputs.each(function (i, input) {
$(this).prop("value",(i % 2 == 0)?++x:++y);
});
});
"" + (i % 2 == 0) ? x++ : y++
is interpreted as (see precedence rules)
("" + (i % 2 == 0)) ? x++ : y++
and ("" + (i % 2 == 0)) is always truthy, because both "true" and "false" are non-empty strings. So in your example, you're using x++ all the time, ignoring the y++ branch.
It seems the associativity of + operator which is from left to right of expression. If you remove ""+ only (i % 2 == 0) makes condition part of conditional operator which will be evaluated to true of false. but if you include it will not evaluated to boolean rather string and would be true always.
With string you will always get true
alert("" + false ? "true" : "false");
Live Demo

What does shorthand "index >= 0 && count++" do?

I was killing time reading the underscore.string functions, when I found this weird shorthand:
function count (str, substr) {
var count = 0, index;
for (var i = 0; i < str.length;) {
index = str.indexOf(substr, i);
index >= 0 && count++; //what is this line doing?
i = i + (index >= 0 ? index : 0) + substr.length;
}
return count;
}
Legal: Think twice before using the function above without giving credit to underscore.string
I put the line alone here, so you don't waste time finding it:
index >= 0 && count++;
I have never seen anything similar to that. I am clueless in what is doing.
index >= 0 && count++;
First part: index >= 0
returns true if index has a value that is greater than or equal to 0.
Second part: a && b
most C-style languages shortcut the boolean || and && operators.
For an || operation, you only need to know that the first operand is true and the entire operation will return true.
For an && operation, you only need to know that the first operand is false and the entire operation will return false.
Third Part: count++
count++ is equivalent to count += 1 is equivalent to count = count + 1
All together now
If the first operand (index >= 0) of the line evaluates as true, the second operand (count++) will evaluate, so it's equivalent to:
if (index >= 0) {
count = count + 1;
}
JavaScript nuances
JavaScript is different from other C-style languages in that it has the concept of truthy and falsey values. If a value evaluates to false, 0, NaN, "", null, or undefined, it is falsey; all other values are truthy.
|| and && operators in JavaScript don't return boolean values, they return the last executed operand.
2 || 1 will return 2 because the first operand returned a truthy value, true or anything else will always return true, so no more of the operation needs to execute. Alternatively, null && 100 will return null because the first operand returned a falsey value.
It's equivalent to:
if (index >= 0) {
count = count + 1;
}
&& is the logical AND operator. If index >= 0 is true, then the right part is also evaluated, which increases count by one.
If index >= 0 is false, the right part is not evaluated, so count is not changed.
Also, the && is slightly faster than the if method, as seen in this JSPerf.
It's the same as:
if(index >= 0){
count++;
}
JavaScript will evaluate the left side (index >= 0), if it's false the && (AND) will short circuit (since false AND anything is false), thus not running `count++.
If it's (index >= 0) true, it evaluates the right side (count++), then it just ignores the output.

Categories

Resources