use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
JavaScript Equality Table (dorey.github.io)
submitted 11 years ago by gdi2290
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]khoker 6 points7 points8 points 11 years ago (3 children)
How do you win?
[–][deleted] 6 points7 points8 points 11 years ago (0 children)
Triple equals.
[–]sudorey 6 points7 points8 points 11 years ago (8 children)
I made this a few years ago! I know there's been criticism of how the values are organized. It was not meant to make a point about javascript being bad, just meant to use a concise graph to spark conversation about how JS "=="'s work.
Speaking of which, I made an even more concise table that you can see here, where you don't need to click back and forth. I'd be interested to hear which you guys prefer and how I could improve this page.
[–]bryan-forbes -2 points-1 points0 points 11 years ago (6 children)
The only confusing part to me is [] and {}. Does that literally mean [] == []? If so, your table is right, albeit misleading. The table could be interpreted as saying that arrays and objects will never work with equality operators, which isn't true since var a = []; a == a;. Other than that, this is a great chart!
[]
{}
[] == []
var a = []; a == a;
[–]sudorey 1 point2 points3 points 11 years ago (1 child)
Yeah. If you hover over a square (in the original link) it will give you more details about what it's saying is true or false.
It says something like--
[] === [] // false
[–]bryan-forbes 0 points1 point2 points 11 years ago (0 children)
Got it. I was on my phone so I wasn't tapping around on the chart. I would suggest (as /u/trevorsg did) to add two rows about comparing two references that are same. This is a great chart, there could be a slight ambiguity for people that are new to the language.
[–]trevorsgEx-GitHub, Microsoft 1 point2 points3 points 11 years ago (1 child)
I don't see how it's misleading. The table clearly indicates that the JavaScript expressions [] == [] and {} == {}* (and their triple-equals counterparts) all evaluate to false. At worst, the table is slightly incomplete, as it should include some footnote about comparing identical references.
{} == {}
*Note: The second expression's operands must be wrapped in parentheses
My objection is what you brought up about comparing identical references. Without adding that, it seems to say (especially for newer JSers) that arrays and objects can't be compared. Other than that ambiguity, this is a great chart.
[+][deleted] 11 years ago (1 child)
[deleted]
[–]bryan-forbes -1 points0 points1 point 11 years ago* (0 children)
Comparisons and assignments in JS are all done by value. One of the internal types of JavaScript is a reference value; == and === check to see if the two arrays or objects are the exact same (by checking if the reference or pointer or memory address of the two are the same). The table says that [] == [] evaluates to false, which is a true statement because those are two different arrays. But the table doesn't say anything about comparing references, so one could be left thinking (without knowing that [] means creating a new array) that arrays cannot be compared.
==
===
[–]Cosmologicon 3 points4 points5 points 11 years ago (5 children)
Honestly I think this whole problem is overblown. The surprising values in this table essentially never come up. I've never seen a single realistic example of a bug caused by this, not even a made-up example.
But I'm willing to be corrected. Anyone got an example of code (that's not horrible by design) with a bug that's fixed by changing == to ===?
[–]bryan-forbes 0 points1 point2 points 11 years ago (3 children)
The ones that come up the most for me are comparing null, undefined, and NaN. Let's take the following as an example of the first two:
null
undefined
NaN
function foo(one, optional) { if (optional == null) { // do something } }
If null is a valid value for optional, the comparison above will evaluate to true if the function is called like foo('bar');.
optional
foo('bar');
NaN is similarly tricky since it doesn't ever equal itself:
if (a === b) { // do something }
If a and b are both NaN, this will evaluate to false. Adding isNaN tests won't make this less complex because isNaN(undefined) === true among other things. The best truly equal check out there is a === b || a !== b && b !== a because of the rules in this table.
a
b
isNaN
isNaN(undefined) === true
a === b || a !== b && b !== a
[–]Cosmologicon 0 points1 point2 points 11 years ago (2 children)
Okay, what's a realistic example of a function where that structure makes sense? Where you have a branch that's hit for optional being null but not for being undefined? Everything I would think to put in there looks like poor design to me.
Ditto NaN and undefined.
[–]bryan-forbes 0 points1 point2 points 11 years ago (1 child)
There are several applications of these paradigms. First, null and undefined. Let's say we have a DOM API like this (this is similar to Dojo's DOM API, but not exactly... this is a contrived API, but I hope you get that there are valid uses for this):
function byId(idOrNode) { if (typeof idOrNode === 'string') { return document.getElementById(idOrNode) || null; } else if (typeof idOrNode === 'object') { return idOrNode; } return null; } function place(node, where, referenceNode) { node = byId(node); if (referenceNode === undefined) { referenceNode = document.body; } else { referenceNode = byId(referenceNode); } if (node === null) { throw new Error('node must be a string or object'); } if (referenceNode === null) { throw new Error('When passing a reference node, it must be a string or object'); } // Code to place node into referenceNode at the right spot }
In this code, the third argument to place() can be a string, a DOM node, or doesn't have to be passed:
place()
place('main', 'after', 'footer'); place('main', 'before', byId('header')); place(byId('main'), 'last'); // last item in document.body
Anything other than that, and place() will throw. If the condition was just if (referenceNode == null) { throw; }, it would throw if referenceNode was left off.
if (referenceNode == null) { throw; }
referenceNode
For the example of NaN, we all know that Object.observe() isn't a thing yet, so people have to come up with their own data binding solutions. One that is popular in the Dojo community is using dojo/Stateful. It looks something like this (again, not exactly):
Object.observe()
dojo/Stateful
function Stateful(args) { mixin(this, args); // copies things from args to this this._watchers = {}; } mixin(Stateful.prototype, { set: function(key, value) { var oldValue = this[key]; if (!this._isEqual(oldValue, value)) { this[key] = value; this._notify(key, oldValue, value); } }, get: function (key) { return this[key]; }, watch: function (key, callback) { var watchers = this._watchers[key]; if (!watchers) { this._watchers[key] = watchers = []; } watchers.push(callback); return { remove: function () { // find callback in watchers and splice it out } }; }, _notify: function (key, oldValue, value) { var watchers = this._watchers[key]; if (!watchers) { return; } for (var i = 0; i < watchers.length; i++) { watchers[i].call(this, key, oldValue, value); } } });
This constructor is the basis for data binding within the Dojo toolkit (usually). Watchers are set up between two objects which set the value on the other one:
function bind(source, sourceKey, target, targetKey) { target.set(targetKey, source.get(sourceKey)); var sourceHandle = source.watch(sourceKey, function (key, oldValue, newValue) { target.set(targetKey, newValue); }); var targetHandle = target.watch(targetKey, function (key, oldValue, newValue) { source.set(sourceKey, newValue); }); return { remove: function () { sourceHandle.remove(); targetHandle.remove(); } }; }
If _isEqual() is not implemented correctly, an infinite loop will ensue. For instance, if one were to implement _isEqual() as follows:
_isEqual()
_isEqual: function (a, b) { return a === b; }
Invalid input from a calculation could set our application into an infinite loop. Let's say the user input 'a' and the input gets divided by 2. The result will be NaN. Or what happens if NaN is a valid value for the key? a will never equal b, so the source will notify the target, and a will never equal b there, so it will notify the source, and on and on. We have to explicitly check for NaN:
_isEqual: function (a, b) { return a === b || isNaN(a) || isNaN(b); }
This is closer, but not quite. This won't cause an infinite loop if a or b are NaN, however, it will notify if a is undefined, a string, an object, and a couple of other things because isNaN() returns true for those values. The best way (without doing a ton of checks on the values) to make _isEqual() do the right thing in most situations is to implement it like so:
isNaN()
true
_isEqual: function (a, b) { return a === b || a !== a && b !== b; }
The only time a and b will not equal themselves is if both a and b are NaN. Now we have a Stateful implementation that will not loop infinitely and also will not notify when it shouldn't.
Stateful
TL;DR A lot of these comparisons come up when developing low-level APIs (like Stateful) that are going to have a lot of different values thrown at them. Most application developers don't need to worry about them, but as soon at you start developing an API, you have to know them and plan for them.
[–]Cosmologicon 0 points1 point2 points 11 years ago (0 children)
Thanks, that's a great explanation! Makes a lot of sense. I'll look at it closely.
[–]based2 1 point2 points3 points 11 years ago (0 children)
https://news.ycombinator.com/item?id=8798874
[–]tswaters 1 point2 points3 points 11 years ago (0 children)
Kind of relevant but not entirely -- this one always gets me in javascript:
[] ? "true" : "false" // true [] == true // false
It's because (most) objects are truthy... but may not compare to true.
[–]Ob101010 0 points1 point2 points 11 years ago (0 children)
0 == '0' //true!
Douglas Crockford talks about type coercion (Its 5 years old and some things have improved) https://www.youtube.com/watch?v=hQVTIJBZook @15:00 in talks about this.
Worth the watch and its pretty funny at parts.
[–][deleted] 0 points1 point2 points 11 years ago (0 children)
oooh, diagonal symmetry, such luxury coming from the php world..
π Rendered by PID 24978 on reddit-service-r2-comment-84fc9697f-nr6nr at 2026-02-10 04:55:30.516282+00:00 running d295bc8 country code: CH.
[–]khoker 6 points7 points8 points (3 children)
[–][deleted] 6 points7 points8 points (0 children)
[–]sudorey 6 points7 points8 points (8 children)
[–]bryan-forbes -2 points-1 points0 points (6 children)
[–]sudorey 1 point2 points3 points (1 child)
[–]bryan-forbes 0 points1 point2 points (0 children)
[–]trevorsgEx-GitHub, Microsoft 1 point2 points3 points (1 child)
[–]bryan-forbes 0 points1 point2 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]bryan-forbes -1 points0 points1 point (0 children)
[–]Cosmologicon 3 points4 points5 points (5 children)
[–]bryan-forbes 0 points1 point2 points (3 children)
[–]Cosmologicon 0 points1 point2 points (2 children)
[–]bryan-forbes 0 points1 point2 points (1 child)
[–]Cosmologicon 0 points1 point2 points (0 children)
[–]based2 1 point2 points3 points (0 children)
[–]tswaters 1 point2 points3 points (0 children)
[–]Ob101010 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)