I am peer reviewing code written in vanilla javascript, and one of the authors occasionally performs a lazy-typecast if statement because he is evaluating values from a REST service that has very sloppy data. Occasionally a value representing money in USD comes back as a string, and sometimes as a number, probably depending on what validation was in place at the time the user entered the data over the years.
So sometimes we get a value of 150 and sometimes we get "150" (without the quotes, if you know what I mean).
The data is just displayed, and there are no math operations done against it: it simply needs to be compared to another number so some display styling can be done.
Instead of writing some function that checks the type of data and forces it to be a uniform type, the developer does something like this:
var baseVal = ReturnsAnIntegerValue(); // returns a number
var retrievedVal = CallToAwfulDataService(); // could return number or string
if (retrievedVal && retrievedVal == baseVal) {
// do stuff
}
else { ...
At first the == made me see a red flag, but when I asked him about it, he said that the initial check for if (retrievedVal && ... would prevent unexpected outcomes from situations where baseVal and retrievedVal are each some combination of null, 0, empty string, or undefined, like this:
if (null && null == undefined) // false | if (null == undefined) // true
if (0 && 0 == "") // false | if (0 == "") // true
if (0 && 0 == "0") // false | if (0 == "0") // true
if (0 && 0 == "") // false | if (0 == "") // true
You get the idea. I feel like this should be bad code because I was taught that the == is bad form, but the code is readable and concise, without the need for an extra function that type-converts just for show. I can't think of a scenario where we are likely to be hurt by it.
Is this bad code? Specifically: what is wrong with it? Is there a better practice for handling this?
edit
I forgot to mention, I have looked at a bunch of SO questions that mostly seem to back up the == is code smell school of thought, but I can't see what is technically risky about this scenario.
You should probably have some "normalize" function, and test cases with data samples from the backend.
Good practices generally assume that "all is fine" with the environment, which isn't your case.
Which ever way you go, you're doomed as far as "good practices" are concerned.
Related
I'm making a chess game. And I'm storing some tiles of the chessboard for some usage in my program in an array. The problem is, when I update the values in the array, and log them onto the console, I can see the values of the array, which are correct. But, upon clicking and checking the actual values in the console, the array shows different values.
I'm using google chrome's console.
I've already seen another stack overflow saying that this is a known "bug", but the developers won't fix it because it's not actually a bug.
Here's what I see in the console:
(2) ["a6", "a5"]
0: "`6"
1: "b6"
length: 2
__proto__: Array(0)
As you see, the values in the array I see are different than the values that are stored in the array. And this causes many other problems in my program which rely on the contents of this array.
What I want to know is if this is common, and also if there is any fix. Or maybe some scenarios where cases like this occur.
Also, I'm still unsure, for the array shown above ^, are the actual values of the array the values I see ("a6" and "a5"), or the wrong values shown internally ("`6" and "b6").
Please help, if this doesn't work, it will be extremely difficult to finish the project I'm working on.
Here is the code I use to update the array:
let moves = [];
if (tile.slice(1, 2) == 7 && b1.board[dd].piece == null && b1.board[d].piece == null) {
moves.push(d);
moves.push(dd);
}
if (tile.slice(1, 2) == 7 && b1.board[d].piece == null && b1.board[dd].piece != null) {
moves.push(d);
}
if (parseInt(tile.slice(1, 2)) > 1 && tile.slice(1, 2) != 7 && b1.board[d].piece == null) {
moves.push(d);
}
if (tile.charCodeAt(0) > 97 && parseInt(tile.slice(1, 2)) > 1 && b1.board[ld].piece != null && b1.board[ld].piece.slice(0, 1) == "w") {
moves.push(ld);
}
if (tile.charCodeAt(0) < 104 && parseInt(tile.slice(1, 2)) > 1 && b1.board[rd].piece != null && b1.board[rd].piece.slice(0, 1) == "w") {
moves.push(rd);
}
console.log(moves);
just to provide some context, I make an array called moves. I push values into the array based on some conditions. Then I log the array onto the console, which is what I showed above.
The if statements are working because the values I see in the array are correct. But as you know, upon clicking and checking the internal values in the console, they are wrong.
The result I am expecting from the console is:
(2) ["a6", "a5"]
0: "a6"
1: "a5"
length: 2
__proto__: Array(0)
How do I fix this problem?
Not sure this is the cause, but when console.log, Chrome and other browser don't output the serialized values of the arrays/objects but just stores the reference on them. Later when you inspect these arrays/objects Chrome will show the current values in those arrays, not the values that were present at the time of logging.
Try logging with console.log(JSON.stringify(thingToLog)). Or even better with console.log(JSON.stringify(thingToLog, undefined, ' ')).
I know i can say that something is true or false but what can I do with it after i did that? There has to be more.
Would be great if someone has got an example.
Code is basically just making decisions about data, and acting on those decisions. That's a gross oversimplification, but it's generally true.
Booleans (and things that can "act" as Booleans) are important because they're what if statements and other conditionals use to decide what to do.
As a very simplified, kind-of real world example, imagine:
var correctPassword = "myPassword";
var enteredPassword = (get the entered password);
if (correctPassword == enteredPassword) {
logUserIn();
} else {
showBadPasswordError();
}
== compares two things (strings in this case), and returns a boolean value indicating whether or not the two strings are the same. In this case, if it returns true, that means the user's password was correct, so it uses that information to decide whether or not to log the user in.
Boolean,
in other words:
Yes/No 0/1 True/False
I am not good with coding since I am also in the beginner zone. But what I understood from most people is that the boolean is defining the current state of something/code.
is the light on? Yes..then in the code it will be "true"
No?...then "false"
You can use this in If statements...like
if (lightOn == true) {
//then do this
}
else if (lightOff == false) {
//then do this
}
Somehow in that matter.
I'm using the following code to compare returned IP address (Using node-restify which is similar to express):
var checkIP = function (config, req) {
var ip = req.connection.remoteAddress.split('.'),
curIP,
b,
block = [];
for (var i=0, z=config.ips.length-1; i<=z; i++) {
curIP = config.ips[i].split('.');
b = 0;
// Compare each block
while (b<=3) {
(curIP[b]===ip[b] || curIP[b]==='*') ? block[b] = true : block[b] = false;
b++;
}
// Check all blocks
if (block[0] && block[1] && block[2] && block[3]) {
return true;
}
}
return false;
};
config.ips contains an array which (as should be obvious from the code) can be specific or wildcarded IPs.
This works, but it seems like there is a more efficient way to do this. Just curious if anyone has any suggestions on a way to simplify this or make it more efficient. My request time nearly doubled when I introduced this and I'd like to squeeze out some load time if possible.
If my intuition is correct, you might be doing a bunch of extra work right now:
For each IP expression in your config.ips array, your code is parsing and comparing:
if (block[0] && block[1] && block[2] && block[3]) {
return true;
}
^^^ Note that you have already done work to get all 4 blocks in the iterations of calculating this expression 4 times per IP: (curIP[b]===ip[b] || curIP[b]==='*'), so the ANDing above is not preventing the overhead of the work that is already happening regardless.
I have 2 ideas for you:
Since IP addresses are strings anyways, the * notation lends itself to be suitable for a Regex to do the work, instead of your splitting and comparing? So maybe as a next step you could look into implementing a Regex to do the work, instead of .split() and compare, and test the performance of that?
Or maybe figure out how to avoid that overhead associated with comparing the parts all the time, and compare the wholes when you can? And then fall back into comparing the parts only when necessity requires it.
If you want to read some C code, here's how Apache does IP blacklisting behind the scenes. Look at the function named in_domain for some inspiration.
Good luck, hope this helps!
Today this question came up for the project I'm working on. The 'problem' is that I have some uncertainties in the data that is provided to me and on top of which I am building my application. This means it could be that some values sometimes are present but sometimes not. Because I want some consistency in my upper layers I wrote some 'sanitize' method that creates the consistency I want.
But...what is better?:
var myNewData = {};
myNewData['somevalue'] = (myOldData.somevalue) ? myOldData.somevalue : '';
or
var myNewData = {};
myNewData['somevalue'] = myOldData.somevalue || '';
And...why is it better? Is it performance? Readability?
Just curious.
EDIT:
To be clear. The 'somevalue' property does not necessarily had to be in the old data. Sometimes it is sometimes it is not.
EDIT2:
Of course, if I know that the value of my old data contains a non-character value (numeric, boolean, etc.) I will default to it's appropriate value (0, true, etc.).
You should aim at readability, and for this case || clearly wins.
The performance in Javascript is very hard to predict because it can vary wildly between different implementations and sometimes the result are apparently totally illogic (something that formally requires three lookups can be faster than something requiring one because may be the runtime engine has been specialized for that code path).
I ran a performance test for this instructions:
myNewData['somevalue'] = (myOldData.somevalue) ? myOldData.somevalue : ''
myNewData['somevalue'] = (myOldData.somevalue) || ''
And as bonus the old if:
if (myOldData.somevalue)
myNewData['somevalue'] = myOldData.somevalue
else
myNewData['somevalue'] = '';
Both for myOldData.somevalue empty or not. For a test like this:
for (i = 0; i < 10; ++i) {
for (j = 0; j < 100000000; ++j) {
result = empty || "";
}
}
Outer loop is to calculate an average (timing code is omitted). These are my results (lower index better performance):
Code | Empty | Not Empty
| IE9 CHROME | IE9 CHROME
------------------------------------------------------
?: | 1435.1 551.1 | 1636.1 706.1
|| | 1450.3 488 | 1623.7 706.4
if | 1436.2 491 | 1642.6 653.6
------------------------------------------------------
So I guess performances aren't the point here (anyway a better test should check what if the variable to test is something more complex).
Readability is something very opinion based. Personally I prefer || because it's clear enough and shorter but if you pick a C programmer maybe he won't like it while a C# programmer will understand it's like his ?? operator...
The problem with:
myNewData['somevalue'] = myOldData.somevalue || '';
is that, if myOldData.somevalue holds an acceptable falsy value, you'd still get the empty string.
So, with the first one you could at least make a strict check to have better control:
(myOldData.somevalue !== false) ? myOldData.somevalue : '';
Both will yield '' if myOldData.someValue is falsey (null, undefined, 0, '', etc), but the first one is very susceptible to copy/paste errors. Use the second form wherever possible and when coalescing all falsey answers to your default value is tolerable.
Note that if the base object -- myOldData -- could be null or undefined, it's a completely different ball game, and you'll need to do something like this:
myNewData.somevalue = ( myOldData && myOldData.someValue ) || '';
This assumes that myOldData is an object. If it's a string or number, bad things could happen here. (And gratuitous parentheses are always a good idea.)
I think both are equally good.
However, take care that they work only for maps containing string values. If the old map contains the value false, null or 0, they would be transformed into an empty string.
Therefore, I tend to prefer the generic case:
myNewData['somevalue'] = (myOldData.somevalue != undefined) ? myOldData.somevalue : '';
However, if you are handling strings only, the short myOldData.somevalue || '' looks concise and straightforward to me.
No difference.
Perfomance? Negligible.
Readability? You could say by yourself, what is easily to read to you and your colleagues. I'd prefer shorter one.
The second one is better in that you don't need to repeat the same thing and less chances you'll get an error. At the same time it is uncommon for people, used static-typed languages before.
What's the difference between & and && in JavaScript?
Example code:
var first = 123;
var second = false;
var third = 456;
var fourth = "abc";
var fifth = true;
alert(first & second); // 0
alert(first & third); // 72
alert(first & fourth); // 0
alert(first & fifth); // 1
alert(first && second); // false
alert(first && third); // 456
alert(first && fourth); // abc
alert(first && fifth); // true
It seems like && is a logical and which gives me always the second value if both are true.
But what is &?
(By the way, && seems to be and in Python; & seems to be & in Python)
& is bitwise AND
This operator is almost never used in JavaScript. Other programming languages (like C and Java) use it for performance reasons or to work with binary data. In JavaScript, it has questionable performance, and we rarely work with binary data.
This operator expects two numbers and retuns a number. In case they are not numbers, they are cast to numbers.
How does it work? Wikipedia has an answer: https://en.wikipedia.org/wiki/Bitwise_operation#AND
&& is logical AND
Most usually, programmers use this operator to check if both conditions are true, for example:
true && true // returns true
true && false // returns false
However, in JavaScript, it is extended to allow any data type and any number of terms. It returns:
First term that evaluates to false
Last term otherwise (if all are true-y)
Here are some examples:
true && false && true // returns false
true && 20 && 0 && false // returns 0 (it is first false-y)
10 && "Rok" && true && 100 // returns 100 (as all are true-y)
&& short-circuiting
As can be seen from above, as soon as you find one that term is false-y, you needn't to care about the following terms. This allows Javascript to stop evaluation altogether. This is called short circuiting.
This statement doesn't alert anything and false is returned:
true && false && alert("I am quiet!") // returns false
Therefore, you could use the && operator as a shorter replacement for an if statement. These are equivalent:
if (user.isLoggedIn()) alert("Hello!")
user.isLoggedIn() && alert("Hello!")
Almost all JS compressors use this trick to save 2 bytes.
& is the bitwise "and". This means that if you have two numbers converted to binary, the result is a number that has the 1 digit at the positions where both numbers have 1.
100011 //35
& 111001 //57
---------
100001 //35 & 57 == 33
To determine whether two boolean values put together are true or false, if you want to check them both (like validation on the web page), you may use the & operator. & is bitwise AND.
With the && operator, once it finds the first value is false, it will end evaluation and not to check the second value.
With all the lofty, detailed insights throughout, they have mostly missed the truth that there is a conditional evaluation where ONLY the single & will work. The practical layman's answer that solved my head beating on an IF statement string of MULTIPLE chained && each !== to a condition was causing FAILURE and needed to legitimately use the single &. I thank Jake Wayne (and Russ) for their unfairly downvoted answer that got it right given that where there is more than one && that !== it has already ceased its evaluation and proceeds no further after the first evaluation is found ==!. With the && it thinks its job is done after the first evaluation shows !== [eg. false]. My failing code was
IF ((sessionStorage.myLable !== "LableStringA") && (sessionStorage.myLable !== "LableStringB") && (sessionStorage.myLableZ !== "LableStringA") && (sessionStorage.myLableZ !== "LableStringB")) { ...)
Here, properly substituting and using a single & for the && it was both practically in the real world and technically the correct answer. Thank you again Jake Wayne (and Russ) for the insight and understanding of code.