Non-nullish logic check for objects - javascript

What is the correct/best way to refactor this logic, using nullish operator? -
if (value !== undefined && value !== null && typeof value !== 'object') {
// error, when not null/undefined, it must be an object
}
UPDATE
So far I've tried this one, which seems to be working, though looks a little odd:
if (typeof (value ?? null) !== 'object') {
// error...
}
Would that be a proper equivalent?
P.S. I'm writing this is TypeScript, so browsers compatibility doesn't concern me.

Although your existing implementation example will work, JavaScript's typeof function has a longstanding history of causing confusion in the case of typeof(null) returning 'object'. One of your most important considerations in refactoring code will always be the maintainability of your code, and any likely source of confusion is likely to reduce maintainability.
If someone were to look at this code right now, particularly any developer who is inexperienced with JavaScript or has never run into the typeof(null) quirk, they would assume that your code is looking for all non-object types, including the values of null and undefined rather than excluding them.
Additionally, although current JavaScript standards are unlikely to change the behavior of typeof(null) to avoid breaking existing code, there's no absolute guarantee that this behavior will never change. There's especially no guarantee that TypeScript itself won't change this behavior to be more intuitive and transcompile down to a different JavaScript equivalent.
You're far better off avoiding confusion in your code as well as potentially future compatibility breaking updates if you modify the default fallback value for your nullish coalescing operation. Specifically, default to {} which is always guaranteed to be interpreted as an object and will be far less likely to be subject to breaking changes in either JavaScript or TypeScript:
if (typeof (value ?? {}) !== 'object') {
// error...
}

Related

Overusing Object.prototype.toString.call?

I just saw a blog post with the code
if(Object.prototype.toString.call(callback) !== '[object Function]'){
return new TypeError(callback + ' is not a function');
};
In this specific situation it looks like over-engineering it since we could use typeof callback. I see no situation, for the purpose of this code, where typeof callback would not give the correct answer. Even more, the prototype could be overridden and start giving wrong answers while typeof can't.
Example would be:
Object.prototype.toString = function(){return '[Object String]';};
Object.prototype.toString.call([])
// logs "[Object String]"
Question: is there any situation (given the purpose of this line, which is to check if a variable is a function) where typeof would fail?
I think its more correct, semantic and not over-engineering to use:
if(typeof callback !== 'function'){
return new TypeError(callback + ' is not a function');
};
The Object.prototype.toString check is from the ES5 and earlier era, when the results of that method could not be forged through a custom Symbol.toStringTag implementation. However even then, if one wanted to be very strict about these tests, they would usually have had to grab a reference to the toString function at initial evaluation time, since Object.prototype.toString can itself be overwritten — as could Function.prototype.call.
Today it would never make sense to perform a type check this way, and you’re correct that even at the time, it wasn’t typically necessary. However in the past there were a number of platform objects in browsers that returned unique strings from typeof, and that was likely one of the motivations for performing a test this way. Today there is only one such weird case remaining: typeof document.all returns undefined, but it is actually a function.
Your instinct to prefer typeof is still correct, though. The case of document.all is probably not worth worrying about in almost any code, and even if it is, the toString check will not be reliable. An example of a real reliable (paranoid) check would be:
var _Object = Object;
function isObject(value) {
return _Object(value) === value;
}
function isFunction(value) {
return typeof value === 'function' || (isObject(value) && typeof value === 'undefined');
}
console.log(isFunction(function() {})); // true
console.log(isFunction(document.all)); // true
So the answer to the part you marked ‘question’ is yes, there is one situation where typeof n === 'function' returns a misleading string, and historically there were additional situations.
More meta, regarding the ‘overengineering’ question: Perhaps the author learned it as a ‘best practice’ at some time in the past and hasn’t reviewed it in a while because, hey, it’s what’s familiar to them and it works, etc. Although there are better options, I wouldn’t call an awkward if condition overengineering. To me at least, overengineering refers to stuff at a higher level than this — architectural choices, etc. Things that are hard to refactor.
Personally, I would suggest that if you’re writing code that performs early input validation a lot, eschewing direct use of typeof might still be a good idea. Testing ‘types’ in JS is often not so straightforward, so a collection of isSomething functions like those in the example above can help abstract away the quirkier implementation details and bring some consistency and readability back. As functions, they’re also more flexible (e.g. arr.filter(isFunction)). There are popular libs that provide such utils and if using them you typically won’t need to worry about how it’s being achieved.

OK to use type coercion when checking for undefined/null?

Is it acceptable to use type coercion (== instead of ===) to check for undefined/null?
What are the downsides? Is there a better way to check for undefined/null?
Clarification: I am looking for a statement that will check for both undefined and null.
test(null);
test(undefined);
function test(myVar) {
if (myVar != undefined) {
alert('never gets called')
}
}
I'm going to attempt to address this question as objectively as possible, but it deals with some mushy "best practices" opinion stuff that can trigger people to forget that there's more than one way to do things.
Is it acceptable to use type coercion (== instead of ===) to check for undefined/null?
It's acceptable to write code however you see fit regardless of anyone who tells you otherwise. Including me.
That's not really helpful here, so let me expand on that a bit, and I'll let you decide how you feel about it.
Code is a tool that can be used to solve problems, and == is a tool within JavaScript code to solve a specific problem. It has a well-defined algorithm which it follows for checking a type of equality between two parameters.
===, on the other hand, is a different tool that solves a different, specific problem. It also has a well-defined algorithm which it follows for checking a type of equality between two parameters.
If one tool or the other is appropriate for your use-case, then you shouldn't hesitate to use the tool.
If you need a hammer, use a hammer.
But if all you have is a hammer, then everything looks like a nail, and this is the core issue with ==. Developers coming from other languages often aren't aware of how == works and use it when === would be appropriate.
In fact, most use cases are such that === should be preferred over ==, but as you've asked in your question: that's not true in this instance.
What are the downsides?
If you relax your standards for === and allow developers to use == you may very well get bitten by misuse of ==, which is why sticking religiously to === may be acceptable to some, and seem foolish to others.
if (val === null || val === undefined) {...
is not particularly difficult to write, and is very explicit about intent.
Alternatively,
if (val == null) {...
is much more concise, and not difficult to understand either.
Is there a better way to check for undefined/null?
"better" is subjective, but I'm going to say, "no" anyway because I'm not aware of any that improve the situation in any meaningful way.
At this point I will also note that there are other checks that could be performed instead of null/undefined. Truthy/falsey checks are common, but they are another tool used to solve yet another specific problem:
if (!val) {...
is much more concise than either of the previous options, however it comes with the baggage of swallowing other falsey values.
Additional notes on enforcement via linting:
If you follow the strictness of Crockford's JSLint, == is never tolerated, in the understanding that a tool that's "sometimes useful" but "mostly dangerous" isn't worth the risk.
ESLint, on the other hand, allows for a more liberal interpretation of the rule by providing an option to allow null as a specific exception.
== undefined and == null are both equivalent to checking if the value is either undefined or null, and nothing else.
As for "acceptable", it depends on who is looking at the code, and whether your linter is configured to ignore this special case.
I can tell you for sure that some minifiers already do this optimisation for you.
The ideal way to test for undefined is using typeof. Note you only need to test them separately if you care about a difference between undefined and null:
test(null);
test(undefined);
function test(myVar) {
if (typeof myVar === "undefined") {
// its undefined
}
if (myVar === null) {
// its null
}
}
If you don't care if its undefined/null, then just do:
test(null);
test(undefined);
function test(myVar) {
if (!myVar) {
// its undefined or null, dunno which, don't care!
}
}

What does undefined === undefined compare?

After reading through Lodash's code a bit and learning that it uses typeof comparisons more often than not (in its suite of _.is* tools), I ran some tests to confirm that it is faster, which it is, in fact (if marginally).
Discussing my confusion with a fellow developer, he pointed out that in case 1:
var a;
return a === undefined;
Two objects undergo comparison, whereas in case 2 (the faster case):
var a;
return typeof a === 'undefined';
is a far more simple and flat string compare.
I was always of the thought that undefined inhabited a static place in memory, and all triple equals was doing was comparing that reference. Who's correct (if either)?
JSPerf Test:
http://jsperf.com/testing-for-undefined-lodash
In this case (with var a in scope), both of the two posted pieces of code have identical semantics as x === undefined is only true when x is undefined and typeof x will only returned "undefined" when x is undefined (or not resolved in the execution context).
That out of the way, we end up with:
undefined === undefined
vs.
"undefined" === "undefined"
So, even in a naive implementation case the "difference" between the two is SameObject(a,b) vs StringEquals(a,b) as per the rules for Strict Equality Comparison.
But modern implementations of JavaScript are quite competitive and, as can be seen, are very well optimized for this case. I don't know of the exact implementation details, but there are at least two different techniques that could allow the performance (in FF/Chrome/Webkit) to be the same for both cases:
ECMAScript implementations may intern strings, such that there is only one "undefined" string. This would make the StringEquals(a,b) effectively the same as SameObject(a,b) which would end up amounting to a "pointer comparison" in the implementation - this alone could explain why the performance is the same.
Additionally, because typeof x === "undefined" is a common idiom, it could be translated during the parsing to end up in a special call that performs the same, say TypeOfUndefined(x). That is, the implementation could bypass the === (and StringEquals) entirely if it so chose.
IE comes out as a the "clear loser" and seems to be missing an applicable optimization here.
The implementation of the undefined value is outside the scope of ECMAScript; there are no mandates that it must be a single value/object in the implementation.
In practice, however, undefined (and other special values like null) is most likely implemented as either a singleton (e.g. "one object in memory") or as an immediate value or value flag (such that there is actually no undefined object).
According to EcmaScript (see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf ) if both expressions are strings (typeof returns a string) it perfroms a string comparison (char by char), otherwise it just compares references (in case when one of the sides is undefined). There is no way that string comparison would be more efficient then simple two numbers (i.e. addresses in memory) comparison. However it is possible that it is highly optimized (browsers do not follow EcmaScript in 100%) so it's really hard to say.
Proper benchmark:
http://jsperf.com/undefined-comparison-reference-vs-string
Note that in your test the initial value of a is undefined (may or may not matter, it seems that it does).
Conclusion: always use
return a === undefined;
It definitely won't be slower and it might be faster. Besides it seems more natural to compare something to a special undefined object rather then to a string.

In node.js is `module` always an object?

When I see examples of how to detect whether a script in running in node vs. running in the browser, I see logic like:
if (typeof module !== 'undefined' && module.exports) {
// do something that applies to node
} else {
// do something that applies to browser
}
The node docs list the global module as being an {Object} which I believe means that typeof module should always be "object". Is that always correct in node? If so doesn't it make more sense to do detection logic like:
if (typeof module === 'object' && module.exports) {
// do something that applies to node
} else {
// do something that applies to browser
}
Yes, in all node versions so far, module has always been an object, and is likely to stay that way for all the 0.x versions. As to whether it makes sense to check for it being specifically an object as opposed to not undefined, it's a matter of style mostly. In the former example, since the code is probably only really concerned with adding properties to module.exports, it is more expressive and less brittle as coded. For example, in a future version of node, maybe module becomes a function. In that case, the former example still works whereas the latter example needs a minor change.
That second snippet would probably work fine. But, no I don't think it makes more sense. You care far more about it existing than you care about what it is. And the standard way to check for existence in javascript is:
typeof myVar !== 'undefined'
So there is a bit of JS convention at work here.

Testing Object/Function existence for cross browser javascript

I would like advice as to best practice in testing object existence for cross-browser compatibility.
There seem to be many ways of testing for object/function/attribute existence. I could use jquery or another library, but for now I want to stick as closely as possible to w3c rather than use what amounts to a whole new language.
What I'm trying to do
I'm trying to write a utility library that tries to stick to w3c methods so I can just call
xAddEventListener(elem, type, listener, useCapture)
for all browsers rather than
elem.AddEventListener(type, listener, useCapture)
just for w3c compliant browsers. If another library already does this, please let me know.
I saw this today:
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Style documents?
A reference to a standards or styles document would also be useful. I've found https://developer.mozilla.org/en/Browser_Detection_and_Cross_Browser_Support
but that was last updated in 2003. It advocates simple
if (document.images)
tests for most existence tests and
if (typeof(window.innerHeight) == 'number')
only with numbers because if(0) would evaluate to false
Examples to inspire comment:
if (myObject)
Can an object or function ever fail this simple test?
if (myObject != undefined)
When is this better than the previous test?
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
Another possibility is:
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
Which in python appears to be becoming the favourite way of dealing with these type of things.
Using exceptions looks potentially much cleaner as you could write easy to understand w3c compliant code, and then deal with exceptions when they come.
Anyway, what do people think? Please can you list the pros and cons of methods you like/dislike, rather than simply advocating your favourite.
It all depends on how specific you want to be / how much you want to assert before calling a function.
if (myObject)
Can an object or function ever fail this simple test?
No, the only values that do not pass an if clause are false, 0, "", NaN, undefined and null. These are all primitives. Objects (including functions) will always pass an if clause.
if (myObject != undefined)
When is this better than the previous test?
If you want to check whether a value is "meaningful", i.e. not undefined or null. For example,
if(numberInputtedByUser) {
// do something with inputted number
}
will fail the if clause if the number is 0, while you probably want 0 to be allowed. In such case, != undefined is a slightly better check.
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
It is a keyword. You can call it in a function-like fashion, though. In its most bare form you can use typeof like this:
typeof myObject
You can, however, add (extraneous) parens since they don't mean anything:
typeof (myObject)
Just like you can do:
(myObject).key
or even:
(((myObject))).key
And you can then remove the space after the typeof if you want, resulting in something that looks like a function call.
As to why to use typeof - you can be even more certain of the type of variable. With the if(...) test, the values that pass can be all kind of things - basically everything except the list I posted above. With if(... != undefined), you allow even more to be passed. With if(typeof ... == 'object'), you really only allow objects which might be necessary depending on what you're processing.
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
=== is really preferred over ==. While differentiating between null and undefined is not always necessary, it is a very good practice to save yourself from the results of quirks like 0 == ''. If you want to check whether a number is 0, then === 0 is the way to go, since == 0 also allows for an empty string (which you might not expect and probably don't want). Even in cases == doesn't cause quirks, you'd be better off using === at all times for consistency and avoiding surprising bugs.
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
This is of course possible and very straight-forward. Note however that try catch is said to be slow. Moreover, you don't really account for why it fails. It's a bit simple-minded (but may work fine).
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Yes, like I said above, the first only passes functions whilst the second allows anything except that list of "falsy" values. One could add Node.addEventListener = 123, and it will pass the if clause in the second case. But IE fails to give a correct typeof result:
typeof alert !== "function"
I bet the same goes for addEventListener so you'd still be avoiding that function even if it exists.
In the end, I would just use a simple if clause. Of course this will fail when you add weird things like Node.addEventListener = 123, but then again you're bound to expect weird things happen.

Categories

Resources