JavaScript - === vs == operators performance
Asked Answered
L

6

41

A few weeks ago, I have read this thread Is < faster than <=? about comparison operators in C. It was said that there is no difference in the performance between < and <= as they are interpreted as same/similar machine commands.

At the same time, in our company's "best practices", it was said that we should always use "===" to compare things instead of "==". So, I started to wonder if this is always appropriate as I am used to using the "==" and "typeof ... == " and do not want to change my way of writing :-]

Note that this is in the context of JavaScript.

So, I have a little research and here Which equals operator (== vs ===) should be used in JavaScript comparisons? it is said that:

This is because the equality operator == does type coercion...meaning that the interpreter implicitly tries to convert the values and then does the comparing.

On the other hand, the identity operator === does not do type coercion, and so thus it does not convert the values of the values when comparing

And I started to wonder if this means that when I use the "===" operator, I will get good performance as no resources will be spent on converting the operands. And after all code is turned into machine commands, does this mean that just as there is no difference in C when you use < and <=, this is the same in JavaScript and other languages?

Leavis answered 11/9, 2012 at 17:21 Comment(9)
The path to hell is paved with micro-optimizations.Melson
"And after all coding is turn into machine commands" But not every same instruction in different languages is necessarily turned into the same machine code.Maxie
Try taking a look a this post: #8045250Masterstroke
Do you want your comparison operator to perform type coercion? No? Then use ===. I don't see a choice here.Scopas
Worth mentioning in 2017 that === is faster than == in V8, when the compiler can prove the types are the same by performing analysis - subsequent runs of the code can shortcut in === that they cannot in ==. This is implementation detail and might change - use whichever operator is correct.Wolffish
@BenjaminGruenbaum do you have a link (docs, webpage...) to this statement ?Avoirdupois
@Avoirdupois Would a link to v8/v8/compiler help? You can also just run this code and dump the assembly to see it requires an extra check if the compiler can't prove the operands are the same typeWolffish
i'll check it thanks ! what about this, which one would be faster "a === false" OR " if (!a) " N @BenjaminGruenbaumAvoirdupois
@Avoirdupois that depends on a lot of things like whether or not the compiler can prove the type of a or not - generally === false is faster but it's important to avoid premature optimizations - they also check for fundamentally different things.Wolffish
I
-4

for js, the === operator will return true if used on string types and the strings are exactly the same characters. For objects it compares the object references, not the contents.

From the ECMA standard:

11.9.6 The Strict Equality Comparison Algorithm The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Undefined, return true.
  3. If Type(x) is Null, return true.
  4. If Type(x) is Number, then a. If x is NaN, return false. b. If y is NaN, return false. c. If x is the same Number value as y, return true. d. If x is +0 and y is -0, return true. e. If x is -0 and y is +0, return true. f. Return false.
  5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
  6. If Type(x) is Boolean, return true if x and y are both true or both false;
Inca answered 11/9, 2012 at 17:26 Comment(6)
This contains some wrong information (and the little edit is too much of an afterthought). There is no requirement that str === str is only true for the same object. "a" + "b" === "ab" is true, but there is no requirement that "a" + "b" is interned to the same object as "ab". While both == and === could "stop early" if the implementation decides both are the same object-value (this would be an implementation-specific optimization that would work in some cases), string values must otherwise be compared character-by-character with ===.Billionaire
So, after all, there is a lot of logic behind this sample equals signs :-] ... Thanks for the answer and the ESMA book link - I find this very interesting.Leavis
The first paragraph is pretty much entirely incorrect. I can provide a detailed explanation, if you're interested. (Have you been writing whit with a different language in mind?)Scopas
@ŠimeVidas it will be useful and interesting to se. I have use other languages too - C/C++/Java/ruby on railsLeavis
@ŠimeVidas : yes, that's why I went off to check the standard! If different languages interpret === differently, then that's a big potential pitfall for programmers.Inca
@Joro The operators ===, and == only differ if the operands are of different types (e.g. String vs Number). If two Object values are compared, they behave the same - obj1 == obj2 is equivalent to obj1 === obj2. Same goes for the other types - str1 == str2 is equivalent to str1 === str2, etc.. That's what the first paragraph got wrong (in the context of JavaScript, at least).Scopas
S
26

I feel an answer with easily verifiable evidence would be best.

These operations are so small that it is difficult to performance test them.

  • == 1648 true
  • === 1629 true
  • control test 1575 true

If you subtract off the control test, it looks like there is a ~30% difference in their speeds on my browser. If you do this multiple times, you can get different answers, but === usually comes up the fastest, which I think is just a testament to just how negligible the difference is.

I think this pretty much proves what others were saying, that the performance difference is a waste of time to think about, but it also shows that === is actually faster. Hopefully this answer can save other people time, those who simply must see proof.

2019 Updates

2019-04-09 Firefox with improved test:

  • == 1383 true
  • === 1167 true
  • control test 429 true

2019-04-09 Chrome with improved test:

  • == 249 true
  • === 248 true
  • control test 248 true

2019-04-09 Edge with improved test:

  • == 22510 true
  • === 20315 true
  • control test 4968 true

Browsers have gotten smarter over the years and it appears my original test has run up against cool optimizations in Chrome and Firefox, rendering it no longer useful. I have made the test more difficult to optimize and increased the number of runs to get meaningful results again. It looks like === is still faster across the board. It is probably still a waste of time to worry about.

var testString = "42";
var testString2 = "43";
var testString3 = "42";
var testNumber = 42;
var testNumber2 = 43;
var testNumber3 = 42;

var testObject = {};
var testObject2 = {};
var testObject3 = testObject;


var start = Date.now();
var result = null;
for(var i = 0; i < 200000000; i++){
	result = 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3
}

console.log("==", Date.now() - start, result);

var start = Date.now();
var result = null;
for(var i = 0; i < 200000000; i++){
	result =
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3
}
console.log("===", Date.now() - start, result);
var start = Date.now();
var alwaysTrue = true;
var alwaysFalse = false;
for(var i = 0; i < 200000000; i++){
	result = 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue
}
console.log("control test", Date.now() - start, result);
Sesame answered 22/8, 2016 at 19:52 Comment(2)
Running here on my browser (Firefox) the values are == 1062 and === 283... but "control test 283" is also 283 (!)... Well, "===" is very faster by interpreting the test. Problem: testing with Chrome, the result is inverse (!). "== 387" "=== 352", "control test 350"... or NodeJS (node v11.9.0) and using modern console.time() console.timeEnd(), something like === 300ms, == 200ms and Nop 195ms (or running 10000000000 loops ===29800ms, ==20040 and nop 20045ms), with "==" near zero. ... Well, I changed code to avoid compiler optimizations, but problem persist...Caliban
Hi @TimDown and Rick, you can confirm that === is faster in Firefox here in this other question... But there it is not an usual performance-check, is a measure of the reality, a way to check what the compilers are doing (in average) to implement the ECMA 262 prescriptions.Caliban
D
18

Firstly, performance simply is not a concern. For any real script, any performance gain of using one operator over the other will be infinitessimally small compared to other bottlenecks in the code (typically DOM manipulation would be the number one target).

Secondly, in many cases, == and === will perform exactly the same steps. When the types of the two operands are the same (two strings or two numbers, for example), the ECMAScript specification has precisely the same steps for the two operators. Therefore if you observe a performance difference between the two operators for operands of the same type in one browser or other environment, it is neither guaranteed nor even probable that you will see a similar difference in another browser.

In the case of typeof, as mentioned in your question, the two operands are guaranteed to be of the same type (string) and both operators will do precisely the same thing, so the only reasons to favour one operator over the other are stylistic.

The JS community as a whole has gone rather hardline on this: the consensus seems to be "never use == and != unless you need type coercion", which is too dogmatic for my tastes.

Domination answered 25/9, 2012 at 12:10 Comment(10)
A lot of times, I have been given a large arrays of data from the server. Imagine one thousand rows, and each value in this row should be compare with something else. If the information is return as string, and I compare it with "==" because it is a "number" after all, that's means 1000 covert operations. That's why I think the performance matters.Leavis
@Joro: I'm not sure I understand your point. If your operands are of different types then === and == will have different behaviour, so there's no choice: you have to use the one that does the kind of comparison you want.Domination
I get your point. I wanted to say that you have to be prepare for any situation. The return records maybe in string format, but after a while and server functions update, then to be return like numbers. So, the better solution according to me will be to use "==" because I will not be depended by the return data format .Leavis
It is not a good answer: not say what is faster, not cite any evidence (no benchmark), only the formal specification, that is not the real implementation of the language.Caliban
@PeterKrauss: I strongly disagree. The language specification dictates how implementations must work. A benchmark showing how a handful of implementations perform today tells you next to nothing about how tomorrow's implementations will perform: an implementation that has significant difference between == and === when comparing operands of the same type has got it wrong and is likely to be fixed in future versions. I also think, as mentioned in the answer, that in nearly all scenarios it's pointless to worry about any potential difference.Domination
Hi, I agree that specification is stable and must be cited... But see the BigInt comparison (what brought me here), that is a new datatype, and is time-consuming with relation to Number. I not need to wait 1 year to the "language implementation stabilization", need only a clue to make sure I did the best, this clue is the benchmark. My comment is also about "good answer", your is not; because the most important is to say "=== is the best", then, after it, complement this information with "ignore very-little differences". Your anser have only a good complement, but is note complete.Caliban
@PeterKrauss: I don't think either == or === is better than the other. When comparing operands of the same type, they are the same, so which one you use is purely a stylistic choice; when comparing operands of different types (such as BigInt and Number), they have different behaviour so there is no choice.Domination
@TimDown, you can't say that a thing is same thing when it is not, it is a false assertion: infinitesimal difference is a difference (and we have have a measure for it!). The measure The Truth, if it is "very very litlle" or "not so litlle" is an opinion (only need to separate it)... you are confusing the two things: 1. "description of the real world" with the "prescription of a norm"; 2. your opinion with the truth.Caliban
@PeterKrauss: I can only reiterate the same points. I accept that one operator may be slightly faster than the other for operands of the same type in a particular browser (although the answer you linked to proves nothing). That is a quirk of the browser and is highly unlikely to be replicated in all environments because the specified behaviour is identical. It's highly unusual to be writing code for one single, unchanging browser so the results in one particular browser are unimportant. This is the last comment I'll make here because SO answers are a bad place for an argument.Domination
@PeterKrauss: I think I was partially wrong about this, specifically "an implementation that has significant difference between == and === when comparing operands of the same type has got it wrong" : it's possible that modern JS compilers are able to optimize === in a way that they can't with ==.Domination
L
4

It doesn't matter what performance you get, === is clearly the better choice in this case. Anything else such as better performance is just the icing on the cake. Besides, the difference either way is minimal.

Loving answered 11/9, 2012 at 17:24 Comment(0)
A
2

The performance difference is negligible, which means you should not waste your precious brain cycles thinking about it. If you really want to know though, you should test.

Use === unless you have a great reason not to (you probably don't).

Apportionment answered 11/9, 2012 at 17:24 Comment(0)
D
2

It's a scripting language. The performance of these operators shouldn't matter so much that you should worry about it, because there's a bunch of other things that consume much more power, like the fact that it runs in a virtual machine, is weak typed, works with a HTML DOM inside a browser...

Besides, both operators do quite different things, so one might not be interchangable with the other in any case.

That said, I think (but have not tested) that === is faster. The reason being, that it only needs to compare the type, and if that matches, compare the raw data. The == operator will try to convert one type to another if they don't match. This will be a more expensive operation in most cases.

And that is fortunate, because in most cases === is the better option. :)

But anyway, you can easily test it (make sure you test multiple cases, both with same type and a couple of different types), but if you don't know how to test it, I'd stop worrying about it altogether. The difference, if any, is not going to kill you.

Dampier answered 11/9, 2012 at 17:25 Comment(2)
While generic, like most of these answers wrt == vs === "performance", I suspect the actual speed of == and === is influenced based upon the values provided. While the == rules "seem longer" or "requiring more operations", it should be considered that == is a "super match" of ===, so that it is always possible to try === rules and stop if there is a match before == rules. Of course, this will ultimately depend upon many other factors, not the least of which is implementation.Billionaire
@pst, that is correct, but if speed is so important that you have to use such double checks, you might want to consider a different language than Javascript. Also, if you are strict with your types (a variable is either, say, an integer or unassigned, but never a string), you can safely use the strict comparison operator. Even in cases where you would need ==, you could alternatively perform a typecast first. I think that makes your code more readable and 'safer', which is more important to me than speed.Dampier
I
-4

for js, the === operator will return true if used on string types and the strings are exactly the same characters. For objects it compares the object references, not the contents.

From the ECMA standard:

11.9.6 The Strict Equality Comparison Algorithm The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Undefined, return true.
  3. If Type(x) is Null, return true.
  4. If Type(x) is Number, then a. If x is NaN, return false. b. If y is NaN, return false. c. If x is the same Number value as y, return true. d. If x is +0 and y is -0, return true. e. If x is -0 and y is +0, return true. f. Return false.
  5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
  6. If Type(x) is Boolean, return true if x and y are both true or both false;
Inca answered 11/9, 2012 at 17:26 Comment(6)
This contains some wrong information (and the little edit is too much of an afterthought). There is no requirement that str === str is only true for the same object. "a" + "b" === "ab" is true, but there is no requirement that "a" + "b" is interned to the same object as "ab". While both == and === could "stop early" if the implementation decides both are the same object-value (this would be an implementation-specific optimization that would work in some cases), string values must otherwise be compared character-by-character with ===.Billionaire
So, after all, there is a lot of logic behind this sample equals signs :-] ... Thanks for the answer and the ESMA book link - I find this very interesting.Leavis
The first paragraph is pretty much entirely incorrect. I can provide a detailed explanation, if you're interested. (Have you been writing whit with a different language in mind?)Scopas
@ŠimeVidas it will be useful and interesting to se. I have use other languages too - C/C++/Java/ruby on railsLeavis
@ŠimeVidas : yes, that's why I went off to check the standard! If different languages interpret === differently, then that's a big potential pitfall for programmers.Inca
@Joro The operators ===, and == only differ if the operands are of different types (e.g. String vs Number). If two Object values are compared, they behave the same - obj1 == obj2 is equivalent to obj1 === obj2. Same goes for the other types - str1 == str2 is equivalent to str1 === str2, etc.. That's what the first paragraph got wrong (in the context of JavaScript, at least).Scopas

© 2022 - 2024 — McMap. All rights reserved.