function findBiggestFraction( a , b ) {
a > b ? console.log("a: ", a): ("b: ", b);
}
var firstFraction = 3/4;
var secondFraction = 5/7;
findBiggestFraction(firstFraction, secondFraction); // a: 0.75
findBiggestFraction(7/16, 13/25); // b: 0.52
findBiggestFraction(1/2, 3/4); // a: 0.75
function findBiggestFraction( a , b ) {
if (a > b) {
console.log("a: ", a);
} else {
console.log("b: ", b);
}
}
var firstFraction = 3/4;
var secondFraction = 5/7;
findBiggestFraction(firstFraction, secondFraction); // a: 0.75
findBiggestFraction(7/16, 13/25); // b: 0.52
findBiggestFraction(1/2, 3/4); // a: 0.75
when I run the first code block it only execute the first call. On the other hand for the second block, it runs all three.
You are missing console.log for b.
a > b ? console.log("a: ", a): console.log("b: ", b);
With the ternary, you're never calling console.log when the condition is false. ("b: ", b) evaluates to b, then you don't do anything with the result.
Roughly equivalent code using an if-statement would be
if (a > b) {
console.log("a: ", a);
} else {
("b: ", b);
}
The mistake is arguably much clearer when you use the more verbose statement. Change the ternary line to
a > b ? console.log("a: ", a) : console.log("b: ", b);
Note that using a ternary to run side effects is generally regarded as bad practice. Either use the ternary inside of console.log to pick what argument to pass in, or use an if-statement.
You're functions are not the same. The first function only prints something if a > b is true. The second function prints either way.
This is a caveat to using the ternary operator. It's very helpful, but can be easy to miss details like you just did.
Summary: Both blocks run both functions, but the first block only prints ~half the time.
Related
When playing around with JavaScript syntax it struck me that the following code will throw an error in SpiderMonkey and V8 engines:
var a = 1, b = 1;
a++++b;
This to me is strange, since the following works perfectly fine:
var a = 1, b = 1;
a+++b; // = 2; (Add a and b, then increase a)
// now a == 2 and b == 1
a+++-b; // = 1; (add a and -b, then increase a)
// now a == 3 and b == 1
In addition, the following would be nonsensical code:
var a = 1, b = 1;
a++ ++b; // throws an error
My argument is now that if a+++b is equivalent to a++ + b, and not to a+ ++b, and a+++-b is equivalent to a++ + -b, then a++++b can only be interpreted as a++ + +b in order for it to be valid JavaScript code.
Instead, the engines insist that a++++b is interpreted as a++ ++b, by operator precedence.
This to me is in contrast with the logic that the engines implements using the / symbol, as explained here, to distinguish between division and regular expressions. An example
var e = 30, f = 3, g = 2;
e/f/g; // == 5
e
/f/g; // == 5
/f/g; // is equivalent to new RegExp("f","g")
Here the argument is that because /f/g does not make sense as division in the last line, it is interpreted as a regular expression.
Obviously the / symbol gets a special treatment, in order to distinguish between division and regular expressions. But then why do ++ and -- not get a special treatment as well? (That is, outside operator precedence)
A second question is why operator precedence is not called only when the code is has multiple valid interpretations.
In the code a++++b you have two distinct statements: a++ and ++b with nothing to combine them. The + operator in the context of a++ + +b is actually a type converter (meant for turning strings into numbers) and has a different order of precedence which follows the others in the list.
This question already has answers here:
Question mark and colon in JavaScript
(8 answers)
How do you use the ? : (conditional) operator in JavaScript?
(20 answers)
Closed 9 years ago.
a = (a == b) ? c: b;
I don't understand. All of them {a, b, c} are variables set with certain value by the programmer.
That is called the ternary operator: that is the same as doing:
if(a == b)
a = c;
else
a = b;
If a equals b then a = c otherwise a = b.
This is a short form for an if and an assignment.
q = x ? y : z
q is the variable you assign to
x is a boolean expression which will be true or false.
If it is true y will be assigned to your variable q
else z will be assigned to q.
This is the ternary operator, which is equivalent to:
if (a == b) {
a = c;
} else {
a = b;
}
The main difference is that if/else consists of conditional statements, while the ternary operator is a conditional expression. In other words, the ternary operator works as if the if/else were returning a value. In some other languages, if/else are expressions as well, so the following would be valid, and indeed equivalent to ?: :
a = (if (a == b) { c; } else { b; }) // not valid javascript
Be sure to check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
The Mozilla Developer Network is a fantastic reference for JavaScript.
if a equal to b then assign c to a , otherwise assign b to a
In english -
If a is equal to b, then a = c. otherwise, a = b
The ?: syntax is a ternary operator. Essentially it means that if a is equal to b than a equals c otherwise a equals b
Is this valid JavaScript? I saw an example where someone used commas in the ternary operator conditions, and it was marked as an error in my editor, and the example didn't run in Chrome. However, it did run in Firefox. Once I converted all the ternary statements to if/else statements, the app ran on Chrome.
a!==b ? (a=1, b=2) : (a=2, b=1)
Edit:
This is the actual statement in the code:
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0
Yes, it's valid, and it runs fine in Chrome:
var a, b, c;
a = 6;
b = 7;
c = a !== b ? (a = 1, b = 2) : (a = 2, b = 1);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);
I'm not saying it's a remotely good idea in code humans are meant to read. :-) I expect jamietre is correct in the comments when he/she says it looks like the result of minification.
The comma operator is a binary operator (an operator accepting two operands). It evaluates its left-hand operand (thus causing any side-effects it has, such as assignment), throws that result away, then evalutes its right-hand operand (thus causing its side-effects if any) and takes that result as its result value. If you have multiple comma operators in a row, the overall expression is evaluated in order, left-to-right, with the final result being the value resulting from the right-most operand evaluation.
And of course, you know the conditional operator (a ternary operator — one accepting three operands) is used to pick one of two sub-expressions to evaluate, on the basis of an initial expression.
So that line is very...expressive...what with a total of seven* different expressions inside it.
So in that example, the result of the overall expression is 2 if a !== b initially, or 1 if a === b initially, with the side-effects of setting a and b.
It's the side effects that make it, in my view, a questionable choice. And of course, there's no reason to use the comma operator if the left-hand operand doesn't have side effects.
* Yes, seven of 'em packed into that overall ternary:
a !== b
the first comma expression
a = 1
b = 2
the second comma expression
a = 2
b = 1
Re your edit with the actual statement, that one works too:
function test(a) {
var b = 7,
d = 1,
e = 2,
f = 3,
g = 4,
h = 5,
i = 6;
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0;
console.log("a = " + a);
console.log("b = " + b);
console.log("d = " + d);
console.log("e = " + e);
console.log("f = " + f);
console.log("g = " + g);
console.log("h = " + h);
console.log("i = " + i);
}
test(0);
test(1);
.as-console-wrapper {
max-height: 100% !important;
}
But wow, I hope this is minified, because if a person wrote that, they must really have a thing against anyone who's supposed to maintain it later... ;-)
Yes:
a=1;
b=2;
a!==b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 1
console.log(b); // 2
and:
a=1;
b=2;
a===b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 2
console.log(b); // 1
As you can analyze, changing the equality operator reacts correctly to our test if you look at the results.
Or you can do this :
b = a!==b ? (a=1,2) : (a=2,1);
Read here about comma operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
Expanding on this topic with ES6 code example. If you're using one side of the TRUE : FALSE argument to iterate thru all cases in one IF, it makes sense to separate the code as if it's a switch | case statement.
Nesting implies that there is branching logic, while it is logically nested, writing nested IF's complicates what we're doing in my example. Like a lawyer over explaining a problem to a jury. IMO, you want to explain the point in it's simplest form. For instance, I find this example the most logical way of expressing nested ifs where the TRUE is executed. The final false is your last else {}
choreDoor is either 0,1 or 2:
choreDoor === 0 ?
(openDoor1 = botDoorPath,
openDoor2 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 1 ?
(openDoor2 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 2 ?
(openDoor3 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor2 = spaceDoorPath)
: false;
If you don't want to use the Comma operator (,) then you can use nested Conditional (ternary) operators instead.
var a = 6;
var b = 7;
var c = (a !== b)? // true
((a = 1 || 1===1)? (b = 2) : null) // will first run a=1, then b=2
: ((a = 0 || 1===1)? (b = 0) : null);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);
Im reading John Resigs "Learning Advanced JavaScript" http://ejohn.org/apps/learn/#10 and came across this function below that I don`t understand.
The function yell is called with an argument of 4. When this is done, the argument 4 is run through the terniary operator. If it is greater than zero, which it is, then we come to yell(n-1) + a
My questions relate to this.
a) does yell(n-1) + a call the function again (i.e. restart it) with an argument of 3.
b) If you do (n-1) + a, you get a result of 3a. Does JavaScript convert 3a to "aaa". I ask this because in the assert line it says yell(4) == "hiyaaaa"
c) after converting it, does it somehow add it to "hiy"? I don`t understand how.
d) if JavaScript does convert 3a to a string of "aaa"s, and somehow manages to add it to "hiy", I don`t understand why yell(4)=hiyaaaa. Yell(n-1) + a = hiyaaa (3as), not hiyaaaa(4"a"s).
As you can see I am totally confused.
function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
assert( yell(4) == "hiyaaaa", "Calling the function by itself comes naturally." );
a) This function is taking advantage of recursion, so yes, the function called again and everything else is pushed on the stack waiting for that return value.
b) No, the function is called with a return value as mentioned above.
c) See Above.
d) It doesn't.
Think of it like this:
function a(val) {
return val + "a";
}
function b(val) {
return a(val) + "a";
}
If you call b("hiya") you'll get hiyaaa. Now instead of calling a different function, call the same one.
a) Yes it calls the function again, so the function is recursive.
b) If one of the operands is a string, + does string concatenation.
c) It returns it.
d) Write the recursion out on paper to better visualise it.
For a), it is known as a recursive function, and yes it is calling self with 3.
For b) you aren't just doing (n-1), you are doing yell(n-1) + "a", and once n =0, yell(0) returns 0.
For c), read the last part of b), i.e. because of the ternary statement, it will return "hiy" once n=0.
For d), see the rest of them.
Try replacing the "a" with the argument supplied to the yell function. Like this:
function yell(n){ return n > 0 ? yell(n-1) + n : "hiy"; }
var x = yell(4); log(x);
assert( yell(4) == "hiy1234", "Calling the function by itself comes naturally." );
So, each value of n is taken and put on a LIFO stack ie 4,3,2,1 and when n becomes 0 "hiy" is on top of the LIFO stack. Then the concatenation is done be popping each value off of the stack such that the string becomes "hiy1234".
Hope this helps.
Bumpfster
Here is a lisp procedure that simply adds 'a' to the absolute value of 'b':
(define (a-plus-abs-b a b)
((if (> b 0) + -) a b))
I think this is beautiful, and I am trying to find the best way of writing this in JavaScript. But my JavaScript code is not beautiful:
var plus = function(a,b) {
return a + b;
};
var minus = function(a,b) {
return a - b;
};
var aPlusAbsB = function(a,b) {
return (b > 0 ? plus : minus)(a,b);
}
The main problem is that I cannot use the + and - symbols as references to the functions they really represent as I can with lisp. Can anyone come up with a more graceful way of doing something like this, or have I hit a language boundary?
Obviously, I can do this:
var aPlusAbsB = function(a,b) {
return a + Math.abs(b);
}
, but this is more of a thought experiment than a pragmatic question.
Is there any way I can get reference to the core functions in the JavaScript language just as if they were user-defined?
It's a very cool idea - would be great for evaluating mathematical expressions but you simply can't set an operator (or the logic behind it) to a variable. Sorry :-)
It depends on what aspects of the lisp implementation you find particularly beautiful. I'll propose another version of your suggestion that I think ends up a little closer to your lisp definition's syntax by doing some dirty things.
// Give ourselves + and - functions to level the playing field with lisp.
Number.prototype['+'] = function(x)this+x;
Number.prototype['-'] = function(x)this-x;
// Now we can have some fun.
var aPlusAbsB = function(a,b) a [b > 0 ? '+' : '-'] (b);
// Some other notable language barrier differences, but not too dissimilar?
// (define (a-plus-abs-b a b) ((if (> b 0) + -) a b))
Though not as elegant as the LISP code, you could create a function dynamically that acts like an operator (on numbers), but it's not.
function op(o) {
return new Function("a", "b", "return a " + o + " b");
}
function aPlusAbsB(a, b) {
return (b > 0 ? op('+') : op('-'))(a, b);
}
Additionally, we can hide the complexity of generating these inside an if wrapper, but that's the closest I can get :)
function is(expr, op1, op2) {
return expr ? op(op1) : op(op2);
}
function aPlusAbsB(a, b) {
return (is(b > 0, '+', '-')(a, b));
}
I think everyone else got here first, but JS is slightly less purely functional than lisp, operators are not functions or objects, but operators.
This is slightly more beautiful than your suggestion, though nowhere near as beautiful as your lisp representation of the concept:
var aPlusAbsB = function(a, b) {
var plus = function(a, b) {
return a + b;
};
var minus = function(a, b) {
return a - b;
};
return (b > 0 ? plus : minus)(a, b);
}
This would be equivalent to the following in scheme:
(define a-plus-abs-b
(lambda (a b)
(let ((plus (lambda (a b) (+ a b))) (minus (lambda (a b) (- a b))))
(cond ((> b 0) (plus a b))
(else (minus a b))))))
Yeah, that's not strictly possible, the closest thing you can do is nest addition and subtraction functions inside.
var aPlusAbsB = function(a, b) {
return (function(a, b) { b > 0 ? a + b : a - b })(a, b);
}
Not exactly the same, but it gets the job done in a sufficiently indirect way.