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.
Related
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.
There is a SonarQube JavaScript Rule (javascript:S2688) which says that the use of a === NaN is a bug because it's always false.
I agree with that but I think to use a !== a instead (this is suggested by SonarQube) is a very bad idea.
It's a funny JavaScript fact but certainly not a "best practice".
What about Number.isNaN(a)? Why is this not the suggested solution? Are there any differences or problems which I've missed?
the use of a === NaN is a bug because it's always false.
This behaviour is not a bug, because it is how NaN has been defined to work. But if you actually used a === NaN in a program then that would be a bug because of the always-false result.
a !== a instead ... is a very bad idea. It's a funny JavaScript fact but certainly not a "best practice".
I disagree with your "certainly". Due to problems with the original global isNaN() function (which I'll explain in a moment), a !== a was, historically the best way to test for NaN. So in fact it is a very common practice to use that technique, and I would expect the vast majority of experienced JavaScript developers to be familiar with it.
NaN is the only value that tests as not equal to itself.
What about isNaN(a)? Why is this not the suggested solution? Are there any differences or problems which I've missed?
The original, global isNaN() function doesn't actually test whether its argument is NaN. Nor does it test if its argument is some other non-numeric value. What it does is first try to convert its argument to a number and then test if the result of that conversion is equal to NaN. This implicit conversion means that, e.g., isNaN("test") returns true even though a string is not equal to the value NaN. And isNaN("") returns false because an empty string can be coerced to 0. If that behaviour is what you're looking for then yes, use isNaN().
So all of that is why ECMAScript 6/2015 introduced a new function, Number.isNaN(), which does test specifically for the value NaN, giving an equivalent result to the old-school a !== a.
As suggested in the comments, for older browsers (basically old IE) that don't support Number.isNaN(), if you want something clearer than a !== a and don't mind longer code you can do this:
typeof a == "number" && isNaN(a)
...which is one of the two Number.isNaN() polyfills suggested by MDN. (The other just uses a !== a.)
I have a timer object written in javascript and my goal is to make it as efficient and fast and thus as accurate as possible.
One of my concerns has to do with a specific case that could generally be applied to all manners of coding and I'm sure has been asked before, I just am not sure what terms to use when searching for it.
My question is which of these 2 cases is faster/more efficient?
Case 1: Assigning a variable some value in a repeated section of code, even when you know the value only needs to be assigned once.
Case 2: Checking the value of the variable, thus conditionally assigning it.
function runOnce(){
timer.someValue = { //some object...};
}
function someRepeatedFunction(){
timer.someValue = null;
//vs
if(timer.someValue){
timer.someValue = null;
}
}
Which of those cases would be faster?
Micro-optimization #1
If you insist on the conditional checking, I would bypass using the == operator (that I think Javascript uses automatically) and go for the === operator.
The identity === operator behaves identically to the equality == operator except no type conversion is done, and the types must be the same to be considered equal.The == operator will compare for equality after doing any necessary type conversions. The === operator will not do the conversion, so if two values are not the same type === will simply return false. It's this case where === will be faster, and may return a different result than ==. In all other cases performance will be the same.
Micro-optimization #2
With respect to the choice between the assignment & conditional checking, it seems logical to go for assignment in the case of using a global variable (like the one you seem to be using). Unless you plan on handling cases in an else situation there's no need to continually check what the current typeof the object or it's value is.
Ok, I've been doing some research and starting using this convention when testing for object types or more apt, detecting typeof ..
({function:1}[typeof somefunc])
and this works, but alas - I tested in IE, error. So, no longer using it.. :-) ,.. but.
So, I reverted to testing in a standard way, no biggie (typeof somefunc === "function" or $.isFunction(somefunc)). But I am curious "why" it doesn't work in IE.
Also, can someone explain why this "does" work in Firefox, or what i mean to say is that the expression is odd to me, I want to know the internals of WHY It works (even though in selective browsers). I don't understand how its backreferencing the function:1 as a test with the typeof?
The JScript parser in IE8 and earlier is following the old ECMAScript 3.1 (1999) rules for object initializers, which require that if you want to use a reserved word (like function) as a property name, it must be in quotes. As of ECMAScript5 (2009), the quotes aren't required anymore because the context is unambiguous. Versions of IE released since the spec was updated (IE9+) do allow you to leave off the quotes.
The difference is that in ECMAscript5, the PropertyName in the object initializer grammar is just IdentifierName, not Identifier. Identifier is an IdentifierName that isn't a ReservedWord. function is a valid IdentifierName, but not a valid Identifier because it is a ReservedWord. More: Identifier Names and Identifiers. But the older spec didn't make that distinction between IdentifierName and Identifier, and so to use function there, you have to put it in quotes. (Thanks to chuckj for reminding me that this changed in ECMAScript5.)
Also, can someone explain why this "does" work in Firefox, or what i mean to say is that the expression is odd to me...
Yes, it's quite odd and anyone working on code using it is likely to stumble on it. It's a short way of writing (typeof somefunc=="function"). Here's what's happening:
The expression creates an object with one property, in this case the property name is function and the value is 1.
The typeof somefunc part is evaluated and returns "function" for a JavaScript function, "object" for a wide range of objects, "number" for a number primitive, "string" for a string primitive, etc.
That property name is used to look up a property on the object created in Step 1. If the property is found, the overall result of the expression is 1, a truthy value. If the property is not found, the overall result is undefined, a falsey value.
So ({function:1}[typeof somefunc]) tests if typeof returns "function" for somefunc. Similarly you can do ({object:1}[typeof someobj]) to check if typeof returns "object" for someobj, or ({string:1}[typeof somestring]) to check if typeof returns "string" for somestring.
Side note: This obscure way of doing the test doesn't perform well at all compared to the straightforward (typeof somefunc=="function"): Test when true | Test when false Unsurprising, given that typeof x == y can be highly optimized by a good optimizing engine. So this way of doing the check is harder to read, longer, no easier to type, and usually slower. Hmmm.... :-)
{function:1} is an object with exactly one key, 'function', mapped to a truthy value, 1. So, ({function:1}['function']) is truthy, but (for example) ({function:1}['string']) is falsy.
Most likely, the reason that IE doesn't support it is that function is a reserved word (as you must know), and IE apparently is getting confused by its use in this context. (If so, this is a mistake in IE: surprisingly, the spec actually does allow reserved words to be used in this context.)
just put function in quotes as function is a reserved keyword but "function" is just a string literal
({"function":1}[typeof somefunc])
should work just fine
but then, why won't you simply use:
(typeof somefunc == "function")
it's shorter and more intuitive
EDIT: Based on everyone's feedback, the original version of this question is more design-related, not standards-related. Making more SO-friendly.
Original:
Should a JS primitive be considered "equivalent" to an object-wrapped version of that primitive according to the ECMA standards?
Revised Question
Is there a universal agreement on how to compare primitive-wrapped objects in current JavaScript?
var n = new Number(1),
p = 1;
n === p; // false
typeof n; // "object"
typeof p; // "number"
+n === p; // true, but you need coercion.
EDIT:
As #Pointy commented, ECMA spec (262, S15.1.2.4) describes a Number.isNaN() method that behaves as follows:
Number.isNaN(NaN); // true
Number.isNaN(new Number(NaN)); // false
Number.isNaN(+(new Number(NaN))); // true, but you need coercion.
Apparently, the justification for this behavior is that isNaN will return true IF the argument coerces to NaN. new Number(NaN) does not directly coerce based on how the native isNaN operates.
It seems that the performance hit and trickiness in type conversion, etc, of directly using native Object Wrappers as opposed to primitives outweighs the semantic benefits for now.
See this JSPerf.
The short answer to your question is no, there is no consensus on how to compare values in JS because the question is too situational; it depends heavily on your particular circumstances.
But, to give some advice/provide a longer answer .... object versions of primitives are evil (in the "they will cause you lots of bugs sense", not in a moral sense), and should be avoided if possible. Therefore, unless you have a compelling reason to handle both, I'd suggest that you do not account for object-wrapped primitives, and simply stick to un-wrapped primitives in your code.
Plus, if you don't account for wrapped primitives it should eliminate any need for you to even have an equals method in the first place.
* Edit *
Just saw your latest comment, and if you need to compare arrays then the built-in == and === won't cut it. Even so, I'd recommend making an arrayEquals method rather than just an equals method, as you'll avoid lots of drama by keeping your function as focused as possible and using the built-in JS comparators as much as possible.
And if you do wrap that in some sort of general function, for convenience:
function equals(left, right) {
if (left.slice && right.slice) { // lame array check
return arrayEquals(left, right);
}
return left == right;
}
I'd still recommend against handling primitive-wrapped objects, unless by "handle" you make your function throw an error if it's passed a primitive-wrapped object. Again, because these objects will only cause you trouble, you should strive to avoid them as much as possible, and not leave yourself openings to introduce bad code.