Test against emptiness fails if number is 0 - javascript

For some reason, my boss changed the data I get in my JS, so, if once I received strings, now I can receive strings or numbers (from 0 to n). There was no problem until today, when I discovered the old code blocks when the number to test is exactly 0.
The reason is this code:
if(myObject.getData()) {
...
}
else {
//here's where I go
}
getData() returns strings and numbers BUT when the number is 0, the if test takes it for a Boolean value and the result is always false, while two lines later, inside the curly braces, I need the number 0 to send it to a server.
What's the best way to check if data is not null, not false, not "", not even Boolean, and "preserve" my 0?

You can introduce an OR into your if statement to check whether it's the numeric value 0 using the strict equality operator (===):
var data = myObject.getData();
if ( data || data === 0 )
Some test cases:
data = "" // false
data = false // false
data = undefined // false
data = 0 // true
data = 1 // true
data = "test" // true

Reversing your requirements it appears you want only non-empty strings and numbers. If that assumption is correct you could use typeof and do something like:
var data = myObject.getData();
if((typeof data === 'string' && data !== '') || typeof data === 'number') {
//...
}
else{
//here's where I go
}
This approach has two key benefits:
It is explicit in what the input format should be so therefore is self-documenting.
It guards against any future input type modifications.

Related

Ternary operator condition

The following code uses the reduce method. It outputs the number of times an element appears in the array. If element appears once then it only outputs 1, otherwise if it is a repeated item then it it is added..
let a = ["a", "b", "c", "a", "b"]
const t = a.reduce((aa, ll) => {
const count = aa[ll];
count
?
aa[ll] = count + 1 :
aa[ll] = 1
return aa
}, {})
console.log(JSON.stringify(t))
// output
// { "a":2, "b":2, "c":1 }
Question is regarding the condition in the ternary operation, specifically the count variable. How is the count variable able to resolve true or false.
The concept is called "Truthy" and "Falsy" respectively. Ie anything that is different from false, 0, -0, 0n, NaN, null, undefined and "" (empty string) can be evaluated to true in Javascript
So your assign var counter = aa[ll] to be the value of the key ll in object aa. That's either a number or undefined. If it's a number !== 0 it's a truthy, if it's 0 or undefined it's falsy. Thus it can be used in a ternary operatator. Depending on the value of counter either the value of the first or the second assignment will be returned (but ignored). The return value of an assignment is always the value of the right hand side ...
While you can use also assignments in the expressions of a ternary operator, I personally wouldn't use it that way but write this assignment as follows
const t = a.reduce((aa, ll) => {
aa[ll] = (aa[ll] || 0) + 1;
return aa
}, {})
(aa[ll] || 0) will return the value of aa[ll] if it's a truthy or 0 otherwise. Thus, in your case, the result of this expression will always be a number >= 0. Then you increase the result by 1 (for the currenct occurence of ll) and assign it back to aa[ll]. This is much shorter than your original code and IMHO much more readable
Heres the answer I found.
"A javascript object consists of key-value pairs where keys are unique. If you try to add a duplicate key with a different value, then the older value for that key is overwritten by the new value."
basically the count variable was checking to see if the new property already exists.

Object does not equal to true or false

So my uploaded media file (event.target.files[0]) does not equal to true or false.
It has a typeof object.
It's part of some form state and I'd like to check the object whether all fields are not empty "".
I thought a JS object should always === true, but maybe this is different for 'files' objects?
=== checks for strict equality, so the two values must be exactly the same.
An object is truthy, but does not equal true, so what you are really doing is { ... } === true, which is false.
If you want to check if none of the object's values are empty, you can filter for empty values:
const empty = Object.keys(theObject).length === 0 || Object.values(theObject).filter(value => {
return value.trim() === '';
}).length > 0;
=== tests for equal value and equal type (ref). typeof(true) is boolean but a file is not a boolean. So the comparison will never yield true.
See also https://stackoverflow.com/a/8511350/4640820
To check the type of a value, you must write
if( (typeof <your value>) == ("<expected type>")){
...
}
For example, a statement like this:
if( (typeof 42)=="number" )
is true.
Reference for most cases of typeof

combine multiple && conditions into 1

Is there a better way in Javascript to do null check on multiple elements I want to
a=null; b=null;....n=null;
So in total I have 14 variables set to null initially and I want to apply just one solution to all of them if they are ```null``.
if (a=== null && b=== null&& c=== null&& d=== null&& e=== null &&...&& n===null){
// set some field to false
}
is there a better way to check for null, as this may get cumbersome if we have more arrays added
Thanks!
Create a an array of arrays, iterate it using Array.every(), and do something if all item values are null:
if([a, b, c, ... n].every(a => a === null)) {
// set some field to false
}
If you're new to JS, in JS, values can be "falsey" or "truthy". if / while / for will run if the value it's supposed to evaluates to "truthy." There are few "falsey" values in JS, and the rest are considered "truthy." The false values are:
undefined
0
NaN
null
''
false
(I believe I got them all. Think of "six sins": there are six of these)
So check the following code, and what their outcomes are:
if(0) console.log('yay') // won't run
if(false) console.log('yay') // won't run
if(null) console.log('yay') // won't run
if('') console.log('yay') // won't run
if(NaN) console.log('yay') // won't run
if([]) console.log('yay') // will run
if('0') console.log('yay') // will run
This is a long winded way of saying if you want to do something based on whether array is empty or not, try the following:
let arr = [1,2,3,4]
if(arr.length){
//do stuff if array is not empty
} else {
// do stuff if array is empty
}
Now to actually solve the problem for you, do the following:
const masterArray = [a, b, c, d, ... , n];
let length = 0;
masterArray.forEach(subarr=>{
length += subarr.length;
})
//At this point, if no array had any elements, length would be 0
if(length === 0){
// do stuff
}

Why do I get a different output when using an if statement in filter as oppose to just return

I am new to JavaScript and I am learning a little about High Order Functions. I was wondering if someone can tell me why:
function filter_list(arr) {
return arr.filter(function(item) {
return typeof(item) == 'number';
});
}
// input = [1,'a','b',0,15] output = [1,0,15]
But
function filter_list(l) {
return l.filter(function(item){
if (typeof item == "number") {
return item;
}
});
}
// input = [1,'a','b',0,15] output = [1,15]
I am having a hard time seeing the difference.
Filter
Filter returns a value if a condition is true and ignores it if it is false
function filter(arr) {
return arr.filter(function(x) {
return x
})
}
const booleans = [false, false, true]
// this logs only "true"
console.log(filter(booleans))
Truthy and Falsy
Additional to true and false there is truthy and falsy. This means that values evaluat to true or false in condition statements. You can read more on mdn
function getBooleanValue(value) {
return !!value
}
console.log('1 gets cast to:', getBooleanValue(1))
console.log('0 gets cast to:', getBooleanValue(0))
Your Code
The second code snippet didn't returns the 0 because it gets cast to false. To get the expected array you have to change the return value from item to true
function filter_list(l) {
return l.filter(function(item) {
if (typeof item == "number") {
return true;
}
return false
});
}
console.log(filter_list([1, 'a', 'b', 0, 15]))
This is the 'beauty' of javascript. At your first example you return a boolean in your filter. the type of item is equal to number or it isn't
In the second example you return the item itself. So you return 1, 0 and 15. Because 1 is true and 0 is false in programming, javascript sees the returning 0 as a filter failure. So it is filtered. In other words, everything different from 0 is true, and 0 is false.
In the second case:
function filter_list(l) {
return l.filter(function(item){
if (typeof item == "number") {
return item;
}
});
}
item 's value is used to filter or not itself. When item is worth 0, it's equivalent to false therefore, it's not included in the result. The function passed to filter expects a boolean result, if you do not return a boolean, you have to understand how javascript will interprete it.
Check it by yourself, 0 is equivalent false, therefore, if you return 0, the element is going to be filtered:
console.log(false == 0)
Filter checks for Boolean values, it will take 0 and 1 as true and false, so if false == 0, the return 0 wont work.
console.log(filter_list([1,'a','b',0,15]));
function filter_list(l) {
return l.filter(function(item){
if (typeof item == "number") {
return item;
}
});
}
This is because JavaScript has falsy values. Javascript takes null, undefined, 0 & false as falsy.
function filter_list(arr) {
return arr.filter(function(item) {
return typeof(item) == 'number';
});
}
// input = [1,'a','b',0,15] output = [1,0,15]
in this function you return boolean after comparing type, in which case each item that returns true in comparison is selected.
while in this function you are returning values instead of result of comparison, since 0 is falsy value it doesn't get selected for your filtered list.
function filter_list(l) {
return l.filter(function(item){
if (typeof item == "number") {
return item;
}
});
}
// input = [1,'a','b',0,15] output = [1,15]
Filter expects you to provide a boolean variable. This is done in your first example. The second example is just possible because Javascript is not using static types. The item 0 interpreted as boolean is false. So if you do return 0, filter does not append the item.
The two examples you have provided are not at all equivalent.
In the first example you are returning the result of evaluating the expression typeof(item) == 'number' which will either be true or false depending.
In the second you have three fairly different possibilities.
The first two are covered by the if statement: if the type of the item is number you are returning the item itself which may be 'falsey' (zero or NaN) and thus fail the filter or 'truthy' (anything but zero or NaN).
But there's also an implicit return of undefined if the type of item is not number. This doesn't have an impact in a filter because undefined is falsey, but you will likely get unexpected results using copying this pattern to use elsewhere and it should be avoided.
It's because the Array.prototype.filter() creates a new array with all elements for which the test function returns a truthy value (see here: Understanding JavaScript Truthy and Falsy)
And because 0 is falsy it's not part of the returned array in the second sample.

Default values for function parameters

These are the instructions to the script I have to write:
function longest(first, second) {
if (first.length >= second.length) {
return first;
} else {
return second;
}
Use the || operator to specify default values for first and second in
the function. If one or both parameters are not specified, the empty
string should be used as the default value.
Once you make your changes, you should be able to test the function as
follows:
console.log(longest('Alice')); // second is undefined - second defaults to the empty string
//Alice
console.log(longest()); // both first and second are undefined - both default to the empty string
//(an empty string)
console.log(longest('hi','hello'));
//hello
console.log(longest('hi', 'me'));
//hi
console.log(longest(''));
//(an empty string)
I don't even know where to begin. Can someone shed some light for me?
Try this:
function longest(first, second) {
var firstDefault = '';
var secondDefault = '';
first = typeof first !== 'undefined' ? first : firstDefault;
second = typeof second !== 'undefined' ? second : secondDefault;
if (first.length >= second.length) {
return first;
} else {
return second;
}
}
Default value
first = first || '';
Or, but that is not defined in the requirement
first = (typeof first !== 'undefined') ? first : '';
Apply this to both arguments
The issue with
function longest(first, second) {
if (first.length >= second.length) {
return first;
} else {
return second;
}
}
if you call it as longest('Alice') is that it spews out an error:
TypeError: Cannot read property 'length' of undefined
because second is undefined, and properties of undefined like .length can not be read.
undefined is actually a thing in Javascript rather than an automatic error like in many other languages. We'll come back to that soon...
The purpose is to get you to thinking about how to fix the function. If the function assigned a blank string in place of undefined, the blank string would have a length, 0, that could be read.
In Javascript the || operator can be used to assign default values to missing variables as follows:
function longest(first, second) {
var defaultValue = '';
var first = first || defaultValue;
var second = second || defaultValue;
if (first.length >= second.length) {
return first;
} else {
return second;
}
}
Now if either first or second is undefined, they will be replaced locally with the value of the defaultValue variable, which here is set to the empty string ''.
The empty string is not an undefined value, it is a string that contains no characters. It has a length, and that length is zero. Now the if statement will not fail when an undefined value is passed.
Now longest('Alice') yields 'Alice'
Bugs
Unfortunately the assignment as shown does not teach you enough about Javascript. It is probably worth knowing about a peculiar Javascript feature: any property whether it is called 'length' or something else can be read from existing objects that do not have that property. This may lead to undesired behavior. The result is a value called undefined, which is a value that things can be in Javascript.
When undefined is compared with a number, the result is always false. Mathematically that's normally impossible. We normally think that if x>1 is false, then x<1 must be true or x is 1. That kind of logic does not work for undefined.
When undefined is compared with undefined the result is also false, unless it is an equality test which is true.
Why does this matter? It relates to bugs in the longest() function above. Number inputs are one example. Strings representing numbers have a length but numbers do not have a length. Reading the length of a number yields undefined. And comparing undefined with a defined number is false. That means we can do this:
longest(1,100) returns 100 Correct.
but
longest(100,1) returns 1 OOPS.

Categories