I have some code which looks like following:
$scope.query.toLowerCase() != 1
If query is not defined - there is an error in the console. Actually the code still produces the result that I want, but what is the right approach of dealing with error? Of course I can check the the variable in advance - but that will lead to more code, not sure of the benefits of hiding errors by having to read more code.
Of course I can check the the variable in advance - but that will lead to more code
Writing more code doesn't make your code bad, unless you are in a code golf competition. If you don't handle your errors and edge cases, then your program will not be reliable. If a line of code throws an error, your code might even terminate prematurely.
An alternative way to deal with possible undefined properties is to define a default value instead of checking if it is undefined.
($scope.query || "").toLowerCase() != 1 // this is enough to fix your expression
or more formally
($scope.query === undefined ? "" : $scope.query).toLowerCase() != 1
This obviously depends on what your purpose is.
Another example:
function add(a, b){
return a + (b || 0); // if b is falsy, assume b is 0
}
add(1, 2); // 3
add(1); // 1
Shortcircuiting is very useful in some cases, but make sure you know exactly how it works because misusing it will create unexpected behaviors.
Its bad practice to do ...
try {
$scope.query.toLowerCase() != 1
} catch(e) {
// do nothing
}
since this obscures errors and if an unexpected error happens you wont know about it which makes debugging a nightmare.
The approved practice is to write a few extra lines of defensive code to protect against the scenario that would lead to an error.
Yes its more verbose but its better than having a codebase which is a nightmare to debug.
in general: I'm outsorcing this task into a tiny helper:
function string(v){ return v==null? "": String(v) }
and I can be sure, that the output is always a String (Type-safety).
string($scope.query).toLowerCase() != 1
In this special case? you are checking against a number, you don't need the toLowerCase()
+$scope.query !== 1
would be even better in this case; an no need to deal with null or undefined.
Related
I'm running into a peculiar typescript error when using the > operator with an optional chaining expression.
Example 1 :
if(a?.length === 3)
Example 2 :
if(a?.length > 0)
In both of the above examples, let's say a is inferred as Array<string> | undefined.
Problem: example 1 is totally fine, but example 2 throws a typescript error TS2532: Object is possibly 'undefined'. The error seems to clear off if I update example 2 to if(a && a.length > 0).
I understand it is something to do with strictnullchecks in TS, but no clue why example 1 works fine and doesn't throw an error.
Is it something basic to do with how === and > operators evaluate? In the browser console, undefined > 0 and undefined === 0 evaluates as false, so I would assume there shouldn't be a problem in the if statement too in example 2, which is not the case.
I would appreciate it if someone could enlighten me on why example 2 throws a TS error.
As described in What does "all legal JavaScript is legal TypeScript" mean?, TypeScript may issue type warnings on code that it considers incorrect. JavaScript is very permissive compared to many other languages, and will happily allow you to do things like use the greater-than > operator to compare two completely unrelated values like undefined and 0. The JavaScript specification interprets undefined > 0 as if it were NaN > 0 (using the "not-a-number" NaN value), and NaN compares as false to everything else, no matter what. So undefined > 0 is well-defined in JavaScript. But is it good JavaScript?
That's subjective, but the whole point of TypeScript is that it attempts to overlay a static type system on top of JavaScript. If JavaScript had a stricter type system, it would definitely support x > y where x and y are both numbers, and it also would support it where x and y are both strings. But anything else is probably a mistake. Or at least that's the stance TypeScript takes.
TypeScript will be happy if you refactor that comparison so that you only use > on two numbers, such as by checking whether a is truthy first:
if (a && a.length > 0) { }
In the particular case you bring up, where optional chaining means you are possibly comparing undefined to a number, there is an open feature request to support it in microsoft/TypeScript#45543. It's marked as Awaiting More Feedback, which means the TS team would want to see more demand for it and the reasoning behind it before thinking of implementing it. If you really want to see it happen, you might want to give the issue a 👍, but pragmatically speaking it is unlikely to make much difference.
In that issue it is mentioned that if you want this behavior right now you could use the non-nullish assertion operator ! to pretend that the possibly-undefined value is not undefined, and this will suppress the error:
if (a?.length! > 0) {}
So if you really need to use this technique instead of the type safe version, you can do so without waiting for an unlikely change to the language.
Playground link to code
For the first example, the === is checking for both value and type, so basically you are checking undefined which is the same type of a after the optional chaining ? so the compiler infers that a is actually undefined, meanwhile > can't be used with an undefined value, so TS gives you that error.
you can prevent this issue by eg. adding a type guard if (a)... or if(a!.length > 0).
Hope that help.
I have some weird inconsistent bug in my code that's very hard to reproduce. It shows up but if I run the same sequence again, it goes away. If I try to debug it, it goes away.
Anyways, I'm wondering if the following could be the culprit
Suppose I have the following code
var myBoolean; // undefined
if( !myBoolean ) {
doX();
} else {
doY();
}
Question is, in the above code, will it run doX() or doY()?
When I test it, it seems to run doX(), but I know that there's a more proper way of checking for undefined.
if( typeof myBoolean == 'undefined' || !myBoolean ) { ...
So my question is, could the improper way of checking myBoolean be causing indeterminism in my code? It's just that I would have to make this code change in a lot of places and I just want to know if this is the issue before doing anything.
The expression !myBoolean will always be true when myBoolean is undefined. However, it will also be true when it's 0, "", false, NaN, or null.
Whether that's OK or not depends on the situation in your program. The sample code you wrote is clearly pointless; since myBoolean will definitely be undefined in that if statement, the if can be eliminated completely. In a real situation, you may know that a variable or object property will be either undefined or an object reference.
A lot of people code defensively as a practice, so such a programmer would be likely to include a more explicit test. Most of the time, it's true that the values null and undefined have the same essential meaning in typical coding situations, so if that's the case then it's safe to write
if (myBoolean == null)
The == comparison will be true only when myBoolean is either undefined or null, and not in any other situations. In other words,
if (myBoolean == null)
is effectively the same as
if (myBoolean === undefined || myBoolean === null)
You may use whichever you prefer of course :)
Every time anyone mentions testing against undefined, it's pointed out that undefined is not a keyword so it could be set to "hello", so you should use typeof x == "undefined" instead. This seems ridiculous to me. Nobody would ever do that, and if they did it would be reason enough to never use any code they wrote... right?
I found one example of someone who accidentally set undefined to null, and this was given as a reason to avoid assuming that undefined isn't overwritten. But if they'd done that, the bug would have gone undetected, and I fail to see how that's better.
In C++ everyone is well aware that it's legal to say #define true false, but nobody ever advises you avoid true and use 0 == 0 instead. You just assume that nobody would ever be a big enough jerk to do that, and if they do, never trust their code again.
Has this ever actually bitten somebody where someone else assigned to undefined (on purpose) and it broke your code, or is this more of a hypothetical threat? I'm willing to take my chances to make my code marginally more readable. Is this a really bad idea?
To reiterate, I am not asking for how to protect against reassigned undefined. I've seen those tricks written 100 times already. I'm asking how dangerous it is to not use those tricks.
No, I never have. This is mostly because I develop on modern browsers, which are mostly ECMAScript 5 compliant. The ES5 standard dictates that undefined is now readonly. If you use strict mode (you should), an error will be thrown if you accidentally try to modify it.
undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError
What you should not do is create your own scoped, mutable undefined:
(function (undefined) {
// don't do this, because now `undefined` can be changed
undefined = 5;
})();
Constant is fine. Still unnecessary, but fine.
(function () {
const undefined = void 0;
})();
No proper code will do such a thing. But you can never know what some wannabe-smart developer or a plugin/library/script you are using did. On the other side, it's extremely unlikely and modern browsers will not allow overwriting undefined at all, so if you are using such a browser for development you'll quickly notice if any code tries to overwrite it.
And even though you did not ask for it - many people will probably find this question when looking for the more common "how to protect against redefined undefined" issue, so I'll answer that anyway:
There's a very good way to get a truly undefined undefined no matter how old the browser is:
(function(undefined) {
// your code where undefined is undefined
})();
This works because an argument that is not specified is always undefined. You can also do it with a function that accepts some real arguments, e.g. like this when you are using jQuery. It's usually a good idea to ensure a sane environment in this way:
(function($, window, undefined) {
// your code where undefined is undefined
})(jQuery, this);
Then you can be sure that inside that anonymous function the following things are true:
$ === jQuery
window === [the global object]
undefined === [undefined].
However, note that sometimes typeof x === 'undefined' is actually necessary: If the variable x has never been set to a value (contrary to being set to undefined), reading x in a different way such as if(x === undefined) will throw an error. This does not apply to object properties though, so if you know that y is always an object, if(y.x === undefined) is perfectly safe.
There's a simple solution to that: compare against void 0 which is always undefined.
Note that you should avoid == as it may coerce the values. Use === (and !==) instead.
That said, the undefined variable may be set by error if someone writes = instead of == when comparing something against undefined.
Only you know what code you use, and therefore how dangerous it is. This question can't be answered in the way you've clarified you want it answered.
1) Create a team policy, disallow redefining undefined, reserving it for its more popular usage. Scan your existing code for undefined left assignment.
2) If you don't control all the scenarios, if your code is used outside situations you or your policies control, then obviously your answer is different. Scan the code that does use your scripts. Heck, scan web for statistics of undefined left assignment if you wish, but I doubt that's been done for you, because it's easier to just pursue answer #1 or #3 here instead.
3) And if that answer isn't good enough, it's probably because, again, you require a different answer. Maybe you are writing a popular library that will be used inside corporate firewalls, and you don't have access to the calling code. Then use one of the other fine answers here. Note the popular jQuery library practices sound encapsulation, and begins:
(function( window, undefined ) {
Only you can answer your question in the specific way you seek. What more is there to say?
edit: p.s. if you really want my opinion, I'll tell you it's not dangerous at all. Anything that would be so likely to cause defects (such as assigning to undefined, which is obviously a well-documented risky behaviour) is itself a defect. It's the defect that is the risk. But that's just in my scenarios, where I can afford to hold that perspective. As I'd recommend you do, I answered the question for my use-cases.
It's safe to test against undefined. As you already mention. If you get to some code that overrides it (which is highly improvable), just don't use it anymore.
Maybe if you are creating a library for public use, you can use some of the techniques to avoid the user change it. But even in this case, it's their problem, not your library.
You can use undefined in your code when coding for browsers supporting ECMAScript 5.1 as it is immutable according to the language specification.
Also see this compatibility table or this caniuse ECMAScript 5 to see that all modern browsers (IE 9+) have implemented immutable undefined.
It's not dangerous at all. It can only be overwritten when running on an ES3 engine and that's not likely to be used any more.
First of all, if your code breaks it's probably not because some other developer out there "is trying to be a jerk" as you put it.
It's true that undefined is not a keyword. But it is a global level primitive. It was intended to be used like this (see "undefined" at developer.mozilla.org):
var x;
if (x === undefined) {
// these statements execute
}
else {
// these statements do not execute
}
The common alternative to that (also from MDN) and in my opinion the better way is:
// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
// these statements execute
}
if(x === undefined){ // throws a ReferenceError
}
Which has a couple of advantages, the obvious one (from the comments) is that it does not trigger an exception when x is not declared. It's also worth noting that MDN also points out that it is important to use === over == in the first case because:
var x=null;
if (x === undefined) {
// this is probably what you meant to do
// these lines will not execute in this case
}
else if (x == undefined) {
// these statements will execute even though x *is* defined (as null)
}
else {
// these statements do not execute
}
This is another often overlooked reason why it is probably better to just use the second alternative in all cases.
Conclusion: It's not wrong to code it the first way, and certainly not dangerous. The argument you've seen that you use as an example against it (that it can be overwritten) is not the strongest argument for coding the alternative with typeof. But using typeof is stronger for one reason specifically: it doesn't throw an exception when your var is not declared. It could also be argued that using == instead of === is a common mistake in which case it's not doing what you expected it to. So why not use typeof?
It seems that the strict equality operator is preferred whenever possible - I put my code in JSLint and got the following feedback.
Code:
function log() {
console.log(arguments.length == 1 ? arguments[0] : arguments);
}
Feedback from JSLint:
Problem at line 2 character 34: Expected '===' and instead saw '=='.
I am curious to know what advantages === has over == here. Basically, .length returns a Number, and 1 is a Number as well. You can be 100% sure, so === is just a redundant extra token. Also, checking for the type whilst you know the types will always be the same has no performance advantage either.
So what's actually the reason behind using === here?
The only reason is that you don't have to think whether the comparison you are doing will involve coercion or not. If you stick to using ===, you just have one thing less to worry about.
Of course not everyone agrees. This is why you can disable specific checks in JSlint, if you are sure of what you are doing.
It's not strictly required, as you know the length function is well-tested. But what if length was a bit buggy, and there was a chance it could return false?
In this situation, both 0 and false would be evaluated as false using the == comparison. To test for false (when there is also the chance of 0 being returned), you need to also check the data type, which is where === comes in.
Well, === is supposed to be infinitesimally faster, as it can fail faster (on type mismatch), but that's deep inside the "pointless microoptimizations" territory.
Realistically, I'd advise for ===, even if you are 105% sure - I've been tripped up by my assumptions too many times ("yes, I am positive they are the ... same ... uh ..."). Unless there's a good reason to turn them off, it is better to keep sanity checks enabled in code than trust to do them in your mind.
I'd love some other opinions on what's more efficient in this code. Basically in the following code, there's a setInterval loop and I need 4 requirements to be true before the code runs in the loop. So in v.1 I wrote an if statement checking all 4. Worked fine.
Then I switched to just using try/catch, with the code I want to execute sitting in try{}. The logic was that during each loop, an exception would be generated but suppressed for each invalid condition. On the final loop where all conditions are true, the code executes and clears the interval.
Either works. I like the try/catch method because there's less conditional code that I need to write and worry about breaking. But I'm worried that try/catch is really inefficient, especially in a setInterval() loop hitting at 100ms. What are some opinions of other bright minds here on SO?
Try/Catch
var intvar = setInterval(function(){
try{
clearInterval(intvar);
jQuery('#'+nav[pageid].t1+'>a').replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));
//set display classes for nav
jQuery('#'+nav[pageid].t1).addClass('selected').find('#'+nav[pageid].t2).addClass('subselect'); //topnav
jQuery('#'+nav[pageid].t3).addClass('selected').find('#'+nav[pageid].t4).addClass('subselect'); //leftnav
}catch(err){}
},100);
IF Block
var intvar = setInterval(function(){
if(typeof jQuery == 'function' && typeof nav == 'object' && typeof pageid != 'undefined' && typeof document.getElementById('leftnav') == 'object'){
clearInterval(intvar);
jQuery('#'+nav[pageid].t1+'>a').replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));
//set display classes for nav
jQuery('#'+nav[pageid].t1).addClass('selected').find('#'+nav[pageid].t2).addClass('subselect'); //topnav
jQuery('#'+nav[pageid].t3).addClass('selected').find('#'+nav[pageid].t4).addClass('subselect'); //leftnav
}
},100);
Exceptions should be used for exceptional circumstances (i.e. things that you don't expect to happen normally). You should not, in general, use exceptions to catch something that you can test for with an if statement.
Also, from what I understand, exceptions are much more expensive than if statements.
Use the if statement. I don't know what the overhead is for a TRY/CATCH, but I suspect it's far greater than evaluating a boolean expression. To hit the TRY/CATCH you will have to: execute a statement, generate an error [with that associated overhead], log the error (presumably), made a stacktrace(presumably), and moved back into the code. Additionally, if you have to debug code near those lines the real error could get obfuscated with what you are TRY/CATCHing.
Furthermore, it's a misuse of TRY/CATCH and can make your code that much harder to read. Suppose you do this for longer or more obfuscated cases? Where might your catch end up?
This is referred to as Exception handling
EDIT: As commented below, you only take the runtime performance hit if you actually cause an exception.
The other answers are correct, try/catch is for exceptional circumstances and error handling. if conditions are for program logic. "Which is faster?" is the wrong question.
A good rule of thumb, if you're doing nothing with the exception, it's probably not an exception!
To figure out which to use, let's break down your if condition.
typeof jQuery == 'function' Is the jQuery() function defined?
typeof nav == 'object' Does the nav global variable contain an object?
typeof pageid != 'undefined' Is the pageid global variable defined?
typeof document.getElementById('leftnav') == 'object' Does the document contain a leftnav element?
The first is clearly an exception. You ain't getting far without a jQuery() function.
The second is also an exception. You're not going anywhere without a nav object.
The third is an exception. You need a pageid to do anything.
The fourth is probably logic. "Only run this code if there is a leftnav element". It's hard to tell because the rest of the code doesn't reference a leftnav element! Only the comments do, a red flag. So it's probably a programming mistake.
So I'd probably do this (with apologies if I'm butchering jQuery):
var intvar = setInterval(function() {
// If there's no leftnav element, don't do anything.
if( typeof document.getElementById('leftnav') != 'object') {
return;
}
try {
clearInterval(intvar);
jQuery('#'+nav[pageid].t1+'>a')
.replaceWith(jQuery('<span>'+jQuery('#'+nav[pageid].t1+'>a').text()+'</span>'));
//set display classes for nav
jQuery('#'+nav[pageid].t1)
.addClass('selected')
.find('#'+nav[pageid].t2)
.addClass('subselect'); //topnav
jQuery('#'+nav[pageid].t3)
.addClass('selected')
.find('#'+nav[pageid].t4)
.addClass('subselect'); //leftnav
}
catch(err) {
...do something with the error...
}
},100);
...but I'd really examine if the leftnav element check is applicable.
Finally, I can't help but comment that this "function" is working with global variables. You should instead be passing nav and pageid into the function in order to maintain encapsulation and your sanity.
I would write the following code:
var startTime = (new Date()).getTime();
for (var i=0; i < 1000; ++i) intvar();
var endTime = (new Date()).getTime();
alert("Took " + ((endTime - startTime) / 1000.0) " seconds");
Then I would try both versions of intvar and see which runs more quickly. I'd do this myself but I don't have the page layout you do so my code wouldn't work.
Some stylistic comments - it doesn't seem necessary to test that jQuery is a function. If it isn't, your webpage is likely messed up such that not running the intvar code will not help you. If you rarely expect the exceptions to be thrown, I'd use the try/catch.
For the provided example where you are wrapping a try/catch around a block of code that should always run anyway (unless if something horrible happens), it is good form to use try/catch. An analogy for you: do you always test "Is the sky Blue?" in your if statement, or would you wrap it in a try/catch that is triggered only when the sky happens to turn Green.
Use the If statement method if you are dealing with user provided input or if the chances of a function not existing is much higher due to something else happening in the code.
Keep in mind that if you don't trigger the exception you don't have any unwinding or backtracking across code. In the example the catch will only execute if something is wrong (jQuery is missing or some such thing), however the if statement method has an evaluation happening on EVERY SINGLE CALL to that function - you shouldn't do more work than you have to.
To directly answer the question, as everyone else has, the try..catch is likely going to be more expensive if there actually is an error.
To point out some additional errors in the code beyond what others have already pointed out:
These two codes are not at all equivalent. To explain, even though the codes appear to do the exact same thing, they do not.
In the case of the if() check, NONE of the code is executed. In the case of the exception handler, each line of code inside the exception handler will be executed. SO, what happens if the error occurs in the second, or the third line? Then you've got something completely different happening in your code than what you get if you check the conditions before executing any of it.
Aside from the answers given, I want to add some thoughts on this subject.
Exceptions that are unforeseen, i.e. the runtime throws an exception, should not be caught with try ... catch because you want to read the message that is thrown in the console.
Try ... catch should IMO be thrown when an exception occurs that your application can foresee in your application logic and you want to perform some custom actions when they do. I.e. you want to be descriptive about it being an exception, and it's not part of the happy flow of the application logic.
For example, you could have a method that validates user input so you could have an isValid method that returns a boolean in which case you would use if ... then.
On the other hand if your performing a certain process, and you know that a certain exception can occur that interrupts the happy flow and you want to handle this, I feel that it is better to throw an exception.
As abstract example, you could have methods that implements some business rules.
Instead of validating every business rule for validity, you could have one custom Exception containing dynamic metadata that can be thrown by each of these methods when validity is breached and handle them appropriately, and continue the happy flow otherwise.
This would translate into something like:
throw new BusinessValidationException(TAG, 'Reason for the validation');
Which IMO is much more descriptive than:
if (!checkValidityBusinessRule())
// doSomething
For a series of business rules.
As for the example, it's my humble opinion that this check shouldn't be happening in the first place and that the given checks are true by default for implementing the method.
if(typeof jQuery == 'function' && typeof nav == 'object' && typeof pageid != 'undefined' && typeof document.getElementById('leftnav') == 'object')
What it means is that you must declaratively ensure that given conditions are true before invoking the given method with side-effects, taking away the necessity to perform the checks at all.
If it so happens that one of the conditions is false, then it will throw an exception to the console, which is actually what you want because as a developer it means that something in your application logic or lifecycle is broken.
My 2 cents, I hope they make sense.