switch, else if & or (Beginner Q) - javascript

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;
}

Related

Identical function leads to different outcomes in different languages

I wrote a function in javascript that is supposed to return the lowest prime number larger than x. Instead it get's caught in indefinite recursion.
function next_prime(x) {
if (x <= 1) {
return 2;
}
y = 2;
z = x + 1;
while(true) {
if (z % y == 0) {
z++;
y = 2;
continue;
}
if(y * y > z) {
return z;
}
y = next_prime(y);
}
}
I didn't understand what was wrong, so I implemented the same function in python, where it worked just fine.
def next_prime(x):
if x <= 1:
return 2
y = 2
z = x + 1
while True:
if z % y == 0:
z += 1
y = 2
continue
if y * y > z:
return z
y = next_prime(y)
I looked over both functions and I'm sure that they are identical, yet in python it works and in javascript it doesn't.
Allthough appreciated, I'm not necessarily looking for help with this specific problem, I'm more so interested in what is actually going on here.
I think the problem is that you are not declaring your variables correctly. In JavaScript, you have to use the keywords let and const - which stand for reassignable and not reassignable variables - when declaring a new variable. When using let in lines five and six, the function works just fine.
You should use strict mode to avoid this common mistake of javascript beginners.
your actual js code with 'use strict'; is rejected :
'use strict';
console.log( next_prime(7) ) // never run on strict mode, otherwise make an infinite loop
function next_prime(x) {
if (x <= 1) {
return 2;
}
y = 2;
z = x + 1;
while(true) {
if (z % y == 0) {
z++;
y = 2;
continue;
}
if(y * y > z) {
return z;
}
y = next_prime(y);
}
}
same code in correct javascript syntax :
'use strict';
console.log( next_prime(7) ) // -> 11
function next_prime(x)
{
if (x <= 1) return 2
;
let y = 2, z = x + 1 // declare y and z as locale
;
while(true)
{
if (z % y == 0)
{
z++;
y = 2;
continue;
}
if (y**2 > z) return z
;
y = next_prime(y);
}
}
explanation : your code is recursive, inside call will change y and z value on parent callers and make an infinite loop

How to Solve modulo using recursion(can't use *, %, / or Math operator)

Below is my code which works perfectly fine, except that I am not allowed to use '*' operator. But in that case, I don't know how to convert the negative number to positive for comparison. One option is to use Math.abs but I am not allowed to use that either.
var modulo = function(x, y) {
if ( x === 0 && y ===0 ) return NaN;
if ( x === y ) return 0;
if ( x === 0 ) return 0;
if (x > 0 && y > 0) {
return x < y ? x : modulo(x-y,y);
}
if ( x < 0 && y < 0 ) {
return x*-1 < y*-1 ? x : modulo(x-y,y);
}
if( x > 0 && y < 0 ) {
return x < y*-1 ? x : modulo(x+y,y);
}
if ( x < 0 && y >0) {
return x*-1 < y ? x : modulo(x+y,y);
}
};
You can flip a number's sign by either using the unary minus operator (-value) or by subtracting the number from zero (0 - value).
Either way, it's possible to implement modulo in a considerably less verbose way than you're doing now:
var modulo = function(x, y) {
if (y === 0) { return NaN; }
if (x < 0) { return -modulo(-x, y); } // -27 % 4 -> -(27 % 4)
if (y < 0) { return modulo( x, -y); } // 27 % -4 -> 27 % 4
if (x < y) { return x; }
return modulo(x - y, y);
};
console.log(modulo( 27, 4)); // 3
console.log(modulo(-27, 4)); // -3
console.log(modulo( 27, -4)); // 3
console.log(modulo(-27, -4)); // -3
console.log(modulo(-32, 8)); // 0
Just for bonus points, here's an implementation for the "true" mathematical modulo, also implemented without /, *, or %:
var mathModulo = function(x, y) {
if (y <= 0) { return NaN; }
if (x >= 0 && x < y) { return x; }
return mathModulo(x - (x > 0 ? y : -y), y);
};
console.log(mathModulo( 27, 4)); // 3
console.log(mathModulo(-27, 4)); // 1
console.log(mathModulo( 27, -4)); // NaN
console.log(mathModulo(-27, -4)); // NaN
console.log(mathModulo(-32, 8)); // 0
I've done this in Brainfuck and there you only have increment, decrement and while not-zero. Here is how you do it with that:
function modulo(n, m) {
function helper(acc, steps, diff) {
if (steps === 0) {
return helper(acc, m, 0);
} else if( acc === 0 ) {
return diff;
} else {
return helper(acc - 1, steps - 1, diff + 1);
}
}
return helper(n, m, 0);
}
console.log(12 % 5);
console.log(modulo(12, 5));
I imagine you can do something like this to change from negative to positive:
function negToPos(a, b = 0) {
return a === 0 ? b : negToPos(a+1, b+1);
}
Here is how it looks like in Brainfuck:
[->-[>+>>]>[+[-<+>]>+>>]<<<<<]
Argument passing is like the current cell and the next contains the divident and divizor and you get the modulus in the third and divide in the fourth. Imagine I've done sqrt and made a lisp interpreter in this :-O
You won't get a divide by zero with any of these but it will keep you warm during the winter. (requires ES6 since it will blow the stack with no TCO)
UPDATE At the time of writing there are no ES6 implementation that I know of. There are only partially complete and some of the features will misbehave compared to the standard. One of the features that most implementation lack is TCO but that doesn't make my ES6 statement wrong since they are not ES6 implementations if not 100% standards compliant. For the not yet ES6 implementations you can see what part if the language they have cared to implement in the compatibility table
You could use the negation operator. For example:
if ( x < 0 && y < 0 ) {
return -x < -y ? x : modulo(x-y,y);
}
Here's how I would do it. You basically only have a few cases:
If y is 0, return NaN
If y is negative, transform to positive.
If x is negative, answer is -modulo(-x, y)
If x is less than y, then the answer is x.
Otherwise, the answer is the same as x - y modulo y (this is the recursive part)
var modulo = function(x, y) {
if (y === 0) return NaN;
if (y < 0) y = -y;
if (x < 0) return -modulo(-x, y);
if (x < y) return x;
return modulo(x - y, y);
};
console.log(modulo(4, 3), modulo(4, 3) === 4 % 3) // 1, true
console.log(modulo(-4, 3), modulo(-4, 3) === -4 % 3) // -1, true
console.log(modulo(4, -3), modulo(4, -3) === 4 % -3) // 1, true
console.log(modulo(-4, -3), modulo(-4, -3) === -4 % -3) // -1, true

If then logic with && ||

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;
}

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.

trying to get offsetTop on window.scroll and then traverse the DOM according to the touched slide

I am creating one page site and then trying to get offsetTop on window.scroll, by which i want to traverse the DOM according to the slide.
a lot of tries.. feeling dumb now..
if anyone can help, would be highly appreciable.
thanks
here is the code and fiddle URL:
$(window).scroll(function () {
var y = $(window).scrollTop(),
a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200;
if (y > a) {
$('h1').html('This is First Slide');
}
if (y > b) {
$('h1').html('This is Second Slide');
}
if (y > c) {
$('h1').html('This is Third Slide');
}
if (y > d) {
$('h1').html('This is Third Slide');
}
else{
$('h1').html('No heading');
}
});
http://jsfiddle.net/A8Hmr/9/
Your logic is correct it's just a miss with the ifs.
I will show the code and explain:
var a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200;
$(window).scroll(function () {
var y = $(window).scrollTop();
if (y > a && y < b) {
$('h1').text('This is First Slide');
}
else if (y > b && y < c) {
$('h1').text('This is Second Slide');
}
else if (y > c && y < d) {
$('h1').text('This is Third Slide');
}
else if (y > d) {
$('h1').text('This is Third Slide');
}
else{
$('h1').text('No heading');
}
});
Demo
1) You don't need to take the offset of the slides on every scroll, since they don't change, you can put them outside of the scroll event, that way it will improve the performance.
2) The problem in the code was the if. Since they were all ifs (and not if/else if) statements, all of theme were checked if they were true. Meaning that if the first one was true the next one will not be true and it will enter in the else statement automaticaly overwriting the if that was true.
So you have to make them if/else if and since once y > a become true it will always be true (untill it goes to y < a) you must have an additional condition if y < b meaning if y is less then the next slide. Ofcourse once again you can use only if/else but what is the point in checking 5 things if only one is correct ? Performance should be a main thing in every js code. ;)
Version 2:
(function(){
var a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200,
h1 = $('h1'),
textChange = ['No heading','This is First Slide','This is Second Slide','This is Third Slide', 'This is Third Slide']
$(window).scroll(function () {
var y = $(window).scrollTop();
if (y > a && y < b && h1.text() != textChange[1]) {
h1.text(textChange[1]);
}
else if (y > b && y < c && h1.text() != textChange[2]) {
h1.text(textChange[2]);
}
else if (y > c && y < d && h1.text() != textChange[3]) {
h1.text(textChange[3]);
}
else if (y > d && h1.text() != textChange[4]) {
h1.text(textChange[4]);
}
else if(y <= a && h1.text() != textChange[0]){
h1.text(textChange[0]);
}
});
})();
Demo
What change here?
1) I wrapped the whole thing in self invoking anonymous function (since it's not a good practice to have global variables).
2) We made a variable outside the scroll event that will hold the h1 so we don't have to go in the dom on every scroll event.
3) We made an array that will hold the text that will change. (and updated the values in the text scroll)
4) We changed the if condition in the if statement to check if the text is already the same so we don't have to change it again. So now it will fire only once instead of firing every time we scroll.
5) We changed the else to else if since it would enter once the text is the same an jump to the else.
Pretty much that should increase the performance a lot.

Categories