Context:
I'm trying to make sure that an object passed to a function is valid before I use it. And I'd like to know if there is any difference between the two approaches, one is more syntactically verbose than the other. If the functionality and behaviors are the same across all JavaScript engines used by modern user agents such Chrome, IE, FF etc., I'd rather use the simpler version. If not, I'd like to use the safe bet so my code behaves as I intended regardless of the JavaScript engine's implementation.
Question:
Given the following function, there are two statements as denoted by comment section.
Does statement 1 yield the same result as statement 2 regardless of the JS engine (or user agents)? And why or why not?
function f(obj) {
if(obj) { // statement 1
console.log('obj is valid');
}
if(obj !== null && obj!==undefined) { // statement 2
console.log('obj is invalid');
}
}
No, they are different.
if (obj) tests for truthy values. In JavaScript everything is truthy except for "", 0, false, NaN, null and undefined (there may be a few more I'm forgetting...)
But what if one of those falsy value is a value you are ok with, such as zero or false? A quantity of zero is a perfectly legit value, as is false for isTotallyLame. So you need a test that allows those values to pass. You need to test for existence.
if (obj!==null && obj!==undefined) tests for existence. Only null or undefined will fail the test. This means that empty string "", zero 0, or even false are valid values because they are a set value.
However, as #Tim notes, the preferred standard test for existence looks like this:
if (typeof obj !== "undefined" && obj !== null)
Related
I've always maintained the practice of checking if a value is undefined using
if (typeof x === 'undefined')
However, a colleague is suggesting that using if (x) { is better.
Is there any difference between these two methods from a computational point of view?
There are at least two differences off the top of my mind:
Checking the type as undefined only checks for undefined, unlike if(x), which checks for any truthy values (e.g. true, a non-empty string, a non-zero number, etc)
You can perform typeof on non-existent variables, even in strict mode. You'll get a reference error if you never declared x and did if(x)
"use strict";
const a = undefined;
const b = "truthy value";
if(a) {
console.log("a in if"); // never executes
}
if(typeof a !== "undefined") {
console.log("a with typeof"); // never executes
}
if(b) {
console.log("b in if"); // executes
}
if(typeof b === "undefined") {
console.log("b with typeof"); // never executes
}
try {
if(c) console.log("this should error");
} catch(e) {
console.log("Can't access non-existent variable");
}
console.log("No error:", typeof c);
When should I use which one?
Generally:
Use if(x) when...
You're checking for a boolean
You're checking for (not) 0
You're checking for a non-empty empty string (probably use if(string.length) instead)
Checking the return value of a function (e.g. a function returns null when there's no result for a query or an object when there is (DOM functions like document.getElementById return null when no element with that ID exists))
Use if(typeof x !== "undefined") when...
You're checking whether an object key exists (if(typeof obj.key !== "undefined")) (the proper way as a commentator pointed out is with Object.hasOwn(obj, "key"))
You're checking whether a variable exists (not sure when or why you would do that though)
Checking whether an argument has been passed
Other uses like when you're writing an Express server and checking user-provided content
Something else I probably forgot...
Something that's useful to keep in mind is that Javascript is dynamically typed, even if it looks like it's just variables. There are a handful of types in JS, and Undefined (with caps) is one, and the only value it can hold is undefined. Think of it like saying you have the Number type and it only accepts 42. This is important to know because JS engines have to observe spec.
The Undefined type has exactly one value, called undefined. Any variable that has not been assigned a value has the value undefined.
There is a lot of variation in application code, but you can know that variables that have not been assigned are of type Undefined with value undefined and not something else. Next to Undefined is Null, which has a single value, null. Null, unlike Undefined, needs to be assigned.
In the spec you'll also the find the table for the result you get for each variable type.
You'll notice that Undefined has its own return value, as well as Boolean, but Null returns "object", which is reported to be a mistake in the original spec that we can't get rid of.
With types out of the way, we get to Boolean coercion, which is how if statements work out the condition. The spec has a table of cases that define when a value should be coerced into true or false.
You'll see that an if clause receives the Undefined type, it returns false. The same happens with Null. There are a few other cases that can also return false even if they are not Undefined or Null.
The Number type with values 0, -0, NaN
The String type with length 0 ("")
The BigInt type with value 0
As others have already answered, applications of the spec come in a few different places. The reasons as for why typeof exists and there is an overlap with the falsey evaluation arise from how the JS engines handle values and perform coercion into Boolean.
First a little bit of context (you can skip this part if you prefer to focus on code).
I joined a new project that will be integrated in a nodeJS's platform. Our team does have experience with JEE enterprise Web Apps. That sets up our background. This new project will consume REST APIs, aggregate some data, implement some business logic and pass these data to front-end consumer. Sort of lightweight microservice architecture.
Some co-workers started to work on the project and I found it that in the source code we do have a lot of code snippet like if (foo != null && foo.property != null) {return foo.property.value;}
Foo being supposed to be an object passed as an argument to a function which would implement that kind of test.
A snippet example will talk more.
Let's pretend that's the response of an API i am consuming. I want to write a small function which would return statusValue if the object does exist, if it's not null or undefined, not empty and the property does exist and isn't blank or empty for instance.
var response = {
"services":[],
"metadata": {
"status": "statusValue"
}
};
That's how it is as for now :
function getStatusValue(response) {
if (response != null && response.metadata != null) {
return response.metadata.status;
}
};
What would be considered as a best JS practise to implement that (we are also using lodash so maybe it's a better option to use lodash internals for that). I am just fearing we are transposing our Java habbits.
Basically i would like to know how to check for null, undefined, empty, blank safely (if that makes sense). What would be the JS best practice for that in 2016 with libraries such as lodash and stuff.
When checking for properties of an object, checking for loose equality to null is not enough.
Loose equality (==) employs type hinting in JavaScript, which attempts converting the members to a common type that can then be used for determining whether they are equal or not.
As such, best practices for JavaScript dictate that strict equality (===) is always to be used, in order to avoid edge-case scenarios or unknown behavior when checking for values or types.
You can find more info about loose vs strict equality here:
https://developer.mozilla.org/en/docs/Web/JavaScript/Equality_comparisons_and_sameness
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators
While this is not a must-have in your function, it is a good practice to follow and develop as a habit, so that on later code the implications of loose equality (==) could be avoided (e.g. avoiding '3' == 3, when a number or string type is expected).
Although considered a downside of the language by some, using null is similar in intent as checking for undefined, but is actually meant to express in the code that the coder is expecting an object (or lack of) to be provided, instead of a primitive type (number, string, boolean, function). This differs from Java, or any other typed language, where null is used for Object type defined variables; but in JavaScript there's no constraining a variable to given type.
You can find out more details about null at MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
In practice, and especially when dealing with values that come outside of a unit - which is the case of any API - is considered a best practice to actually check for the type being an object, in order to make sure it has properties.
While your code is not incorrect, it does show that there's not much attention to best practices, which eventually will lead to writing buggy code.
My suggestion for your code, following best practices and independent of any library, is:
function getStatusValue(response) {
// must be of type `object`, to have properties.
if (typeof response === 'object' &&
// any variable of type `object` might be `null`, so exclude that.
response !== null &&
// `metadata` property must be of type `object`, to have properties.
typeof response.metadata !== 'object' &&
// `metadata` is of type `object`, check for not being `null`.
response.metadata !== null) {
// `status` property is expected to be a string, given by the API spec
if (typeof response.metadata.status === 'string' &&
// on strings, we can access the `length` property to check if empty string (0 chars).
response.metadata.status.length > 0) {
// all good, return `status` property.
return response.metadata.status;
} else {
// `status` property is either not a string, or an empty string ('').
}
} else {
// invalid `response` object.
}
}
Also, it might be easier to create or use from any libraries you integrate, a function to check for a valid object; something like _.isObject or this:
function isObject(o) {
return (typeof o === 'object' && o !== null);
}
which you could later be used in the above snipped like so:
function getStatusValue(response) {
if (isObject(response) && isObject(response.metadata)) {
if (typeof response.metadata.status === 'string' &&
response.metadata.status.length > 0) {
return response.metadata.status;
} else {
// `status` property is either not a string, or an empty string ('').
}
} else {
// invalid `response` object.
}
}
As a final thought, as it is clearly visible, following best practices does increase the size of your code, but the benefit is that the resulting code is much safer, with less chances of throwing exceptions (root of many app crashes), easier to collaborate on, and easier to build tests/coverage for.
Using Lodash, you can use the _.isNil(response) function documented here.
In general, I would check a variable like this:
if (typeof x !== 'undefined' && x !== null) {
// x has some value
}
You should not check whether x === undefined because if x is undefined, you'll get a dereference error.
I would implement this using the following function:
var response = {
"services":[],
"metadata": {
"status": "statusValue"
}
};
function getStatusValue(res) {
if (res && res.metadata)
return res.metadata.status || 'not found';
else
return 'not found';
}
console.log(getStatusValue(response));
The if statement will return false if res or res.metadata are undefined and if they both exist, it will return res.metadata.status only if it's defined or 0, otherwise it'll return 'not found'.
Here is a (more concise) way to do such a thing with just JS:
var obj = ...;
var val = obj && obj.prop && obj.prop.val;
val will be undefined/null if either obj or obj.prop are; otherwise it will be obj.prop.val.
This works because of the short-circuit evaluation of &&. It's literal behavior is this: if the first operand is falsey, it evaluates to the first operand. Otherwise, it evaluates to the second. This works as expected for booleans, but as you can see, it can be useful with objects.
|| has similar behavior. For example, you can use it to get a value, or a default if the value is falsey (e.g. null):
var val2 = val || "not found";
Note that this would evaluate to "not found" if val is anything falsey, including 0 or "".
In JavaScript code I want to replace the double-equals structure of the following if-statement:
if( name == null ) {
//do stuff
}
The double equals fail for the jshint rule "eqeqeq", where it's recommended to replace double equals with triple equals. For a moment, let's imagine the above code changed from == null to === null like this:
if( name === null ) {
//do stuff
}
This would work for a variable explicitly defined having the value null, but unfortunately would fail for any unset variables like this.
var a = null; // works correctly
var b; // will fail in comparison
Previously when the triple-equals rule was important to me I would do the following
if( name === null ||| typeof(name) === 'undefined' )
but I find this extremely bloated.
The best alternative I can come up with now is to use the nature of the if-statement and let it evaluate to a false-ish expression like here where I negate the expression and simply remove the == null part:
if( !name ) {
//do stuff
}
For me, this is much simpler, easy to read, and completely avoids explicit equals comparison. However, I am uncertain if there are any edge causes I am missing out here?
So the question is, can I generally replace == null with the negated expression if statements? If so, what are the pitfalls and exceptions where it wouldn't work? Does it work for general array items, strings, object properties?
My criteria for picking a solution will be
clean code
easy to read and quickly understand
validates jshint rules
works in modern browsers (as of writing January 2015)
I am aware of other slightly related questions for discussing difference in the equality operators == vs ===, but this is merely for a discussion of the evaluation compared to null-ish inside the if-statement.
So the question is, can I generally replace == null with the negated expression if statements?
Probably not universally, no, but perhaps in some places.
If so, what are the pitfalls and exceptions where it wouldn't work? Does it work for general array items, strings, object properties?
The !value check will be true for all of the falsey values, not just null and undefined. The full list is: null, undefined, 0, "", NaN, and of course, false.
So if you have name = "" then
if (!name) {
// ...
}
...will evaluate true and go into the block, where your previous
if (name == null) {
// ...
}
...would not. So just doing it everywhere is likely to introduce problems.
But for situations where you know that you do want to branch on any falsey value, the !value thing is very handy. For instance, if a variable is meant to be undefined (or null) or an object reference, I'll use if (!obj) to test that, because any falsey value is good enough for me there.
If you want to keep using JSHint's === rule, you could give yourself a utility function:
function isNullish(value) {
return value === null || typeof value === "undefined";
}
The overhead of a function call is nothing to be remotely worried about (more), and any decent JavaScript engine will inline it anyway if it's in a hotspot.
I have a simple function in my library that checks the validity of an object reference (object here meaning, a reference to a created HTML element, mostly DIV's). It looks like this:
function varIsValidRef(aRef) {
return ( !(aRef == null || aRef == undefined) && typeof(aRef) == "object");
}
While experimenting i found that this has the same effect:
function varIsValidRef(aRef) {
return (aRef) && typeof(aRef) == "object";
}
I understand there are some controversies regarding the short hand () test? While testing against various datatypes (null, undefined, integer, float, string, array) i could find no difference in the final outcome. The function seem to work as expected.
Is it safe to say that these two versions does the exact same thing?
No, in my opinion these functions don't work the same:
First option
If aRef is not undefined or null and the type of the var is object it returns true.
Second option
First we convert aRef to a boolean. Values like null, undefined and 0 become false, everything else become true. If it is true (so not one of those values) it checks if the type is object.
So the second option return false if aRef is 0, something you don't want. And it isn't option a elegant way to check it, because you check if an object or string or something is equal to a boolean.
And at least they don't return the same thing. The first option returns a boolean, but the second option returns the value you put in the function if (aRef) is false:
varIsValidRef(0);
>>> 0
varIsValidRef('');
>>> ""
varIsValidRef(undefined);
>>> undefined
varIsValidref(null);
>>> null
Because JavaScript use these values as falsy values you don't see the difference between these return values if you use if statements or something like that.
So I suggest you to use the first option.
they are strongly different:
!(aRef == null || aRef == undefined)
this part is evaluated to false with any of these "null", null, "undefined", undefined
(aRef)
while this other with any of these 0, "", false, null, undefined, NaN
Interesting case, but it seems logical for both to behave the same way despite being totally different. Lets see the first staement.
return ( !(aRef == null || aRef == undefined) && typeof(aRef) == "object");
Here,
null and undefined both denote a false state combined with the ! infront, makes it equal to the expression aRef which will return true in case both are either not null or not undefined.
They don't do the same, though they end up with the same results.
The first function is more strict in what it will count as false together, or if it's not, if its an object.
The second function will check if aRef is !false or not any of the falsy values (ie [], null, undefined) and check if the type is an object if it isn't.
I would prefer the first function, since its stricter in what it accepts, but if its all the same the function which performs the best should be used.
As for the controversy, its true that you have to be careful about how/when you use falsy values in equations but if it does what you want it to do (and for that you'll need to know what falsy values are) and you implement it correctly it should be no problem. The two are hard to put together though. So with that, if this does what you want it to do, and nothing more or less, by all means use it.
var boolTrue = true;
var randomObject;
if (boolTrue)
// this will fire
if (randomObject)
// this will fire, because the object is defined
if (!objectNotDefined)
// this will fire, because there is no defined object named 'objectNotDefined'
Coming from a C++ and C# background, I am very familiar with the basic if(expression) syntax. However, I think it is not very readable to have both expressions (true/false) and have object existence also being a expression. Because now if I see a function like below, i don't know if the data coming in is an object (existence/undefined check) or a boolean.
function(data) {
if (data)
// is this checking if the object is true/false or if the object is in existence?
}
Is this just the way it is? I mean, is there anyway to easily read this? Also, where is this documented anywhere in the JS spec (curious)?
In Javascript everything is "true" (or "truthy" to be more precise using Javascript parlance) except false, 0, undefined, null, NaN and empty string.
To avoid confusion use:
if (data === true) // Is it really true?
and
if (typeof data === 'undefined') // Is the variable undefined?
You can check for (non-)existence separately:
if ( typeof variable == 'undefined' ) {
// other code
}
However, the syntax you show is commonly used as a much shorter form and is sufficient in most usecases.
The following values are equivalent to false in conditional statements:
false
null
undefined
The empty string ”
The number 0
The number NaN
It checks whether it is truthy.
In JavaScript, everything is truthy except false, 0, "", undefined, null and NaN.
So, true will pass, as well as any object (also empty objects/arrays/etc).
Note that your third comment is true if you mean "declared but not defined" - a variable that has never been declared throws a ReferenceError on access. A declared, non-defined variable (var something;) is undefined (so, not truthy) so it will indeed pass the condition if you negate it.