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 :)
Related
I've been looking to at some old javascript on a website I run - hands up, I know very little about javascript.
I came across the following function:
var timeout = null;
function textareaResize() {
if (typeof(timeout))
clearTimeout(timeout);
timeout = setTimeout(function () {
refreshAutoGrowFields();
}, 200);
}
The intellisense tells me that the syntax typeof(timeout) is invalid, to be more specific 'unexpected constant condition', however this means nothing to me.
I'd appreciate it if someone could explain what should actually be there (if the intellisense is correct in its assumptions).
I'm not sure where that function was found, but it's definitely confusing, because it's actually inaccurate JavaScript.
What it's trying to do is make whats called a timeout, meaning a performance of a certain action or collection of code after a period of time.
In order to do this, it's attempting to set this "timeout" function to a pre-defined variable called "timeout".
The thing is, before they are setting it to the variable "timeout", for some reason they want to make sure that timeout hasn't already been set. Perhaps by setting it twice to setTimeout, it would potentially cause multiple functions to happen within the same amount of time (but perhaps not).
Anyways, in order to do that, they were trying to check if "timeout" has been set before.
The problem is the way they are checking it typeof(timeout), is completely incorrect, for 2 reasons.
First, the term "typeof" isn't usually to be used like a function call; rather, it is a keyword, much like var or return, so it shouldn't in general be used with ()s like it's used here, instead it should be used like typeof timeout == "null", but the problem is that even such a syntax would be completely invalid, because even if it was null, it wouldn't evaluate to "null", it would evaluate to "object", just try pasting the following JavaScript into a console:
typeof null
It should say "object", even typeof undefined is "undefined", which is a string, which, when put in an if statement, would still evaluate to true relatively speaking, so the if statement checking if timeout is defined or not was done completely wrong.
Instead, that if statement should simply be changed to if(timeout), removing typeof completely.
typeof will return the type of the variable you put inside.
These are some types in JavaScript
number
string
boolean
array
object
undefined
you can use the type as
let s1 = 'somevalue'
cosole.log(typeof(s1)) // prints 'string'
you can play around with that and change the contents of s1. Now to the comparing part, if you try something like
if(typeof(s1)=='number')
dothis()
else if (typeof(s1)=='string')
dothat()
tip : both are same
typeof s1
typeof(s1)
and typeof(typeof(someVar)) is always string, that's why the == operator works
Hope it helped and didn't confuse you further.
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.
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?
I've just been looking at the _.isEqual function of Underscore.js and a section of the code goes something like this:
if (a === b) return true;
if (typeof a !== typeof b) return false;
if (a == b) return true;
I'm just wondering if there's any case where the third statement could be reached and evaluate to true?
Edit: Just to be clear, this isn't my own code I'm talking about, I'm reading the source of Underscore, in particular, this line and I was curious about why they're doing that.
I've just been browsing through the Underscore repo and came across a short discussion where someone asked the exact same thing, and it looks like it is actually unnecessary.
Following the algorithm defined by the ECMAScript Language Specification in section 11.9.6 and section 11.9.3 seems to show that no pair of values should return true in the above case.
So, in short, no, that situation is not possible.
The only situation where == and === react unexpectedly is when comparing a literal string ("123") to a constructed string (new String("123")), which would fail the first test.
However, on the second test it gets caught because the constructed string has the type object, but the literal has the type string.
Based on that, I'd say no, the third statement can never be reached, and evaluate to true.
When you use the == operator and the expressions are of different types, JavaScript will generally convert the two into the same type before comparing.
For example, this can happen with null and undefined. null == undefined is true, even though null === undefined is false. However typeof null is "object", while typeof undefined is "undefined". So, in this case you should return false on the second statement.
You can read all the details in the spec (section 11.9.3), it is very involved:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
My initial guess was that it was to work around a broken browser implementation.
However after digging into the git logs for that file it looks like the corresponding line was in the very first underscore.js checkin. (I'm not gonna hunt in the parent documentcloud core.js repo...) You can see it at line 334 of https://github.com/documentcloud/underscore/commit/02ede85b539a89a44a71ce098f09a9553a3a6890 .
So now my guess is that its just cruft that got left in, never completely tested and never cleaned out.
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.