If then logic with && || - javascript

Can someone explain to me or point me to documentation as to why the following function doesn't work?
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if ((x && y && z) === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
I know that I can type it out the long way as follows:
var x = 1;
var y = 2;
var z = 1;
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
console.log(logicTest())
But I'm really trying to understand why the first doesn't work and also if there is a better way of typing the second if/then statement or if that is just the way it will always have to be.
Thanks!

The expression
((x && y && z) === 1)
first involves the evaluation of (x && y && z). To evaluate that, JavaScript tests, in sequence, the values of x, y, and z. If, left to right, one of those values when coerced to boolean is false, evaluation stops with that (uncoerced) value as the value of the whole thing. Otherwise, the value of that subexpression will be the value of z, because it's the last subexpression in the && sequence.
In this case, x, y, and z are all non-zero numbers, so the overall result will be 1, because z is 1.
What you seem to want to be able to do is test whether all of a set of subexpressions are equal to the same value. That, as you've found, can only be determined by explicit comparison. It's also something that could be done by creating a list and then using array functions to perform the tests, which would be useful when there are more than just three subexpressions to test.
Also, on a stylistic note:
function logicTest() {
if (x === 1 && y === 1 && z === 1) {
return true;
} else {
return false;
}
}
Performing tests with relational operators like === generates boolean values. It's more concise to take advantage of that:
function logicTest() {
return x === 1 && y === 1 && z === 1;
}

Related

Find the Greatest Common Divisor

Here is the question.
Find the greatest common divisor of two positive integers. The integers can be large, so you need to find a clever solution.
The inputs x and y are always greater or equal to 1, so the greatest common divisor will always be an integer that is also greater or equal to 1.
Here is my solution.
function mygcd(x, y) {
//your code here
let gcd = [];
let lowestNum;
let bigestNum;
//detect the lowest and bigest numbers
if (x < y) {
lowestNum = x;
bigestNum = y;
} else if (x > y) {
lowestNum = y
bigestNum = x;
} else {
lowestNum = x
}
//check if the bigest num has a modolo == 0
//else loop the lowest num and push in the array
if (bigestNum % lowestNum === 0) {
return gcd += lowestNum;
} else {
let arrNum = []
for (let i = 1; i < lowestNum; i++) {
// console.log(i)
arrNum.push(i)
}
//loop the array backwards
for (i = arrNum.length - 1; i >= 1; i--) {
if (lowestNum % arrNum[i] === 0 && bigestNum % arrNum[i] === 0) {
console.log(arrNum[i])
if (gcd !== 0) {
return
} else {
// gcd += arrNum[i]
let vals = gcd.push(arrNum[i])
console.log(typeof(vals))
}
}
}
}
console.log(gcd)
return gcd[0];
}
console.log(mygcd(30, 12))
The above solution works for the test cases i tried it for, but the issue is that it returns the correct divisor and undefined.
This is what my logs look like
6
undefined
6
undefined
The test cases
test:
Log
6
expected undefined to equal 6
so it gets undefined instead of 6 or the correct divisor.
I also tired a different recursive approach below.
Note: This works well.
function mygcd(x, y) {
if (!x) return y
if (!y) return x
return mygcd(y, x % y)
}
console.log(mygcd(30, 12))
console.log(mygcd(8, 12))
But i am curious to understand why my original solution breaks. Any help would be really appreciated.
Thanks

switch, else if & or (Beginner Q)

I have a function which appears to always be returning true on the first condition irrelevant of input. I have been reading about using switch versus else if as I have 16 conditions to check and I want to ensure I have working 'best practice'
Can I achieve the same thing using both options:
function lsaupdateTotals() {
var x = variablename.value;
var y = variablename2.value;
if (x = 1) || (y = y > 1 && y < 280) {
rdlsa = 7.45;
} else if (x = 2 || (y = y > 281 && y < 460)) {
rdlsa = 11.65;
/ or switch: /
switch (x) {
case 1:
case y > 1:
case y < 280:
y = 7.45;
break;
}
There are several problem in your code:
In javascript, to compare 2 numbers (or strings) you have to use the syntax ===, so if (x = 1) should became if (x === '1') (as I'm expecting x is a string).
The if condition should be in a parenthesis: if (x = 1) || (y = y > 1 && y < 280) { => if ((x === 1) || (y === y > 1 && y < 280)) {
It's not clear what you mean with y = y > 1 (or y === y > 1) in first if (second parenthesis)
In switch/case syntax you cannot use y>1, please refer to switch/case syntax (internet is full of documentation)
When you put an assignment into the if (using = instead of ===) the if statement consider true the condition if the value after the = is not null, 0, empty string, false or undefined, for this reason when you write if(x=1){ the condition is always true.
You've got a few issues in your code:
You're using = instead of == or === to check equality in your if statements. A single = sign always means "set equal to", not "is equal to?".
In your if statement your parens make things a bit ambiguous. It's possible that this works just fine, but wrapping the entire question in parens is guaranteed to work as intended while also being completely clear.
Rewriting your if statement according to the above:
if (x == 1 || (y == y > 1 && y < 280)) {
rdlsa = 7.45;
}
else if (x == 2 || (y == y > 281 && y < 460)) {
rdlsa = 11.65;
}
(EDIT: Note that the y == y > 1 part is almost definitely not doing what you want it to. That's asking "is y the same thing as y > 1?")
In your switch, think of the value in each case as being a place holder for what you're putting into it. So in your example, using y>1 doesn't make sense to evaluate against x, because it's asking if x is *equal to y>1, but y>1 is always true or false and is independent of x.
you are getting the conditions wrong.
Please replace your code with the below lines
function lsaupdateTotals() {
var x = variablename.value;
var y = variablename2.value;
if ((x == 1) || (y > 1 && y < 280)) {
rdlsa = 7.45;
} else if ((x == 2) || (y > 281 && y < 460)) {
rdlsa = 11.65;
}
/ or switch: /
switch (x) {
case 1:
case y > 1:
case y < 280:
y = 7.45;
break;
}

Function to create new array producing undefined

I am trying to write a program that creates an array and populates it with a range of numbers. The function range's x, y, z variables correlates to the start number, the end number, and the number value of each step. My goal is produce an array with all the numbers between (and including) x and y that is created with each step. Here is the code:
let newarray = []
function range (x, y, z){
if (x === undefined || y === undefined || z === undefined || (x > y) || (z < 0)) {
return newarray; // returns empty array if x, y, or z is undefined, x is greater than y or z is a negative integer
}
else if (y > x) {
for (x; x < y; x = x += z) {
newarray.push(x); //pushes x into an array then adds z into x and loops until x exceeds y
}
}
else {
return newarray; //prints out new array
}
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));
right now it is producing undefined for all three numbers. My research suggests something about asynchronicity? I'm not sure what that means.
A few things are at play here:
newArray should be defined inside the function scope rather than as a global variable. Otherwise, subsequent calls to the function will keep appending onto the same array, which is likely not your intention (and if it was, there's array.concat() for that).
Your last else is unreachable, so the function will either return an empty array for input failing your validation or return undefined when control reaches the end of the function after populating the array in the else if block.
x = x += z is probably intended as x += z.
You should disallow z === 0 otherwise you'll wind up with an infinite loop.
Normal JS style is to camelCase variable names.
Additionally, I find it's easier to write positive conditionals than negative conditionals. In this case, enumerating what arguments are allowed seems cleanest. This approach enables you to only have one return statement and fewer conditional branches, mitigating potential confusion.
Here's a version that addresses these issues:
function range(x, y, z) {
const newArray = [];
if ([x, y, z].indexOf(undefined) < 0 && x < y && z > 0) {
for (; x < y; x += z) {
newArray.push(x);
}
}
return newArray;
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));
Note that the section where you check else if (y > x) does not have a return. When this condition is true, your function returns undefined. To fix the problem, just add return newarray; as the last line in the function. Then remove all other lines with return new array;.
The else block is not required as it will be unreachable and will
return undefined.
Corrected x = x + z from x = x += z.
The array declaration was outside, so every time the old data will be
appended with newer data from the for loop.
function range (x, y, z){
let newarray = [];
if (x === undefined || y === undefined || z === undefined || (x > y) || (z < 0)){
return newarray;
}
else if (y > x) {
for (x; x < y; x = x + z){
newarray.push(x);
}
}
return newarray;
}
console.log(range(0, 10, 2));
console.log(range(10, 30, 5));
console.log(range(-5, 2, 3));

x >= x pattern in JavaScript

When reading source of D3.js I saw x >= x pattern. If it is for detecting NaNs among numbers, why not just isNaN(x) or x == x?
Source, where I encountered it:
d3.min = function(array, f) {
var i = -1, n = array.length, a, b;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
}
return a;
};
From my investigations, d3.min is supposed to work on any kind of orderable values, not only numbers. isNaN would only work numbers.
d3 was actually using == at some point. This commit introduced the x == x test:
Unlike Math.min and Math.max, it doesn't make sense to return negative or positive infinity for d3.min and d3.max; the D3 functions return the minimum value according to an arbitrary ordering, not by numeric value. Instead, the minimum or maximum of an empty array, or an array that contains only degenerate values, should always be undefined.
This commit changed x == x to x <= x (which was later again changed to x >= x):
In addition to NaN, which is not equal to itself, you can have objects that are not orderable due to defined valueOf functions which return NaN. For example:
var o = new Number(NaN);
Here, o == o is true, but o <= o is false. Therefore it was possible for d3.min, d3.max and d3.extent to observe these non-orderable values rather than ignore them as intended. The fix is to check !(o <= o) rather than o == o.
OK, I see that x >= x gives false for both NaN and undefined. (Unlike isNaN(x) or x == x.)
EDIT: While it is one of the use cases of x >= x, in this case (thx #Felix Kling for pointing this out) undefined is already being checked.

Extended Ternary expression

I know you can do ternary expressions in Javascript for an if - else statement, but how about an else- else if- else statement? I thought that surely this would be supported but I haven't been able to find any info about it and wasn't able to get it to work just hacking around.
In contrast to Robby Cornelissen's answer - there is no problems with readability if you format it properly (and not writing PHP, since it messed up the operator by making it left-associative in contrast to all other languages that have that construct):
var y =
x == 0 ? "zero" :
x == 1 ? "one" :
"other";
EDIT
What I was looking for is a shorter version of "if expression 1 is true, return expression 1. Else if expression 2 is true, return expression 2. Else return expression 3". Is there no clean way to do this?
There is: expression1 || expression2 || expression3. (It would have been nice if you had put this into your question in the first place.) This is commonly used for default values:
var defaults = null;
function hello(name) {
var displayName = name || (defaults && defaults.name) || "Anonymous";
console.log("Hello, " + displayName + ".");
}
hello("George");
// => Hello, George.
hello();
// => Hello, Anonymous.
defaults = {};
hello();
// => Hello, Anonymous.
defaults.name = "You"
hello();
// => Hello, You.
However, it is important to be aware of the conditions for truthiness. For example, if you expect "" or 0 to be a valid value that does not need to be replaced by a default, the code will fail; this trick only works when the set of possible non-default values is exactly the set of truthy values, no more and no less. E.g.
function increment(val, by) {
return val + (by || 1); // BUG
}
increment(10, 4);
// => 14
increment(10, 1);
// => 11
increment(10);
// => 11
increment(10, 0);
// => 11 <-- should be 10
In this case you need to be explicit:
function increment(val, by) {
return val + (typeof(by) === "undefined" ? 1 : by);
}
I wouldn't recommend it because of readability, but you could just nest ternary operators:
var y = (x == 0 ? "zero" : (x == 1 ? "one" : "other"));
This would be the equivalent of:
var y;
if (x == 0) {
y = "zero";
} else if (x == 1) {
y = "one";
} else {
y = "other";
}
You can extend a ternary condition if you're good. It gets to be messy though.
var number = 5;
var power = 2;
var ans = Math.pow(number,power);
var suggest = ( ans == 5 ? 5 : ans == 10 ? 10 : ans == 15 ? 15 : ans == 25 ? "works" : null);
console.log(suggest);
I may have added to many because I'm on my phone haha but try it in your developer panel.

Categories