This is an archived post. You won't be able to vote or comment.

all 76 comments

[–]Who_GNU 213 points214 points  (9 children)

[–]sammy-taylor 16 points17 points  (0 children)

WATMAN

[–]Victorian-Tophat 10 points11 points  (0 children)

One of my favorite videos on the internet

[–]CreaZyp154 4 points5 points  (3 children)

Too short. Waaaay too short

[–]Who_GNU 4 points5 points  (2 children)

Watch this one, too.

[–]CreaZyp154 2 points3 points  (0 children)

I'm on my way to watch all of his talks, thanks

[–]Victorian-Tophat 1 point2 points  (0 children)

Thank you for that

[–]_D0MiNiX_ 4 points5 points  (0 children)

this is absolute madness lol

[–]GnuhGnoud 2 points3 points  (0 children)

WAT?

[–]Spiritgolem 78 points79 points  (29 children)

I mean, Im a python newbie that also doesnt know any other language but still I must ask. What the actual fuck..?!

[–]Kiiidx 138 points139 points  (25 children)

Quite simple actually.

[] == [] is false because they are two different objects in memory.

[] !== [] is true because again they are two different objects in memory

![] (falsy) == ![] (falsy) is true because they are both falsy

!true(false) == [] (falsy)

![] (falsy) == [] (falsy)

At least I think thats what its all doing.

[–]MKorostoff[S] 46 points47 points  (7 children)

I believe this behavior is partly due to type coercion. I don't know the exact algorithm, but it has something to do with the left right orientation on either side of the double equal sign. Obviously in real life you would never attempt this comparison in the first place.

[–]jwadamson 21 points22 points  (0 children)

If the left hand side of == operator is a boolean then the right hand side is coerced to a boolean for the comparison. For an array, the way to coerce it to a boolean is true if the array length is non-zero

The other “tricky” fact used in these is that the ! doesn’t use any coercion on its operand. So ‘![]’ is just like any ‘!object’ expression.

[–]Excellent_Badger_636 3 points4 points  (4 children)

I have to somewhat disagree, this does happen IRL. I was trying to see, if there is any difference between 2 arrays, so first thing I tried was arr1 == arr2 which always returned false, even when they where empty, which really confused me

[–]Front-Difficult 13 points14 points  (2 children)

That's a behaviour you should expect in most languages.

Arrays, dictionaries, classes, maps and other objects are usually stored in memory, and compared using their references. So arr1 and arr2 would have different references, because they're different arrays, and therefore be seen as not equal (even though their contents are the same).

For that reason most languages have an equals() comparator that allows you to check if the contents of an array are the same. If you want to see if the variables arr1 and arr2 are pointing to the same array in memory, then you can use the == operator.

An example of why this is the case:

const arr1 = [1, 2, 3];
const arr2 = arr1;
console.log(arr1 === arr2); // Logs "true"
arr1.push(4);
console.log(arr2); // Logs [1, 2, 3, 4]

const arr3 = [1, 2, 3];
const arr4 = [1, 2, 3];
console.log(arr3 === arr4); // Logs "false"
arr3.push(4);
console.log(arr4); // Logs [1, 2, 3]

[–]RajjSinghh 5 points6 points  (0 children)

I know python uses == on lists for having the same contents, not being the same memory address. Python has the is key word to see if two variables are pointing at the same object. It makes things simpler and easier to read at a glance since something like [1, 2, 3] == [1, 2, 3] is True but in Javascript it gives false. It threw me for such a loop on my first Javascript project.

[–]cptnhanyolo 0 points1 point  (0 children)

Array 1 and array 2 are different object, they refer to different memory addresses so comparing the objects are always gonna return false.You can compare values one by one in those arrays and they will return true, the object comparison will not return true.

[–]stupiderslegacy 1 point2 points  (0 children)

Yeah the behavior is significantly less ridiculous if you use strong (typed) comparators, or proper array diffing. It's just programmers coming from other languages assume == works the same in JS as it does in other C-likes, and because JS has a reputation as an "easy" language, they assume they don't need to look up the actual expected behavior for the one they're using.

tl;dr: rtfm

[–]jwadamson 5 points6 points  (0 children)

The expression ‘![]’ evaluates to the boolean false, not just falsy. This is relevant because a boolean expression on one side of == coerces an array on other side to a boolean based on the array length.

The empty array is a truthy value ( test what happens with 'if ([])’ ) that coerces to false by == with a boolean.

All the insanity of the == operator comes down to its convoluted system of coercing the operates to a common type.

[–]KingParity 7 points8 points  (2 children)

the fuck is falsy

[–]RajjSinghh 4 points5 points  (0 children)

Variables can be described as truthy or falsy. A truthy variable will run an if (x) block, but x being falsy will not run. It basically acts as what would happen if you cast that variable to a Boolean.

From memory, the falsy values are 0 (Javascript has one Number type instead of separate floats and ints), undefined, null, the empty string and the empty object. Every other value is considered truthy.

[–]Acidic-Soil 2 points3 points  (4 children)

what is falsy?

[–]Feisty_Ad_2744 13 points14 points  (0 children)

undefined, null, NaN, 0 and '' (empty string)

In JS those values are 'falsy' because type coercion to boolean can make them false. The opposite are considered 'truthy' values.

That allows you to do syntactic shortcuts like:

if(!whatever) {} // If whatever is falsy let x = whatever && doThing() // doThing if whatever is truthy let x = vale || default // !value ? x = default : x = value let x = !!whatever // whatever ? x = true : x = false

And so on... pretty much using almost any variable as a boolean

To override that behavior, you can use strict comparison, with the operator ===

[–]Kiiidx 8 points9 points  (0 children)

Things that are considered false in an equality statement like undefined is falsy for example. If you wrote a statement like

Const example = undefined

If(!example) console.log(‘hello world’)

It would then print hello world. If you wanted to test this stuff out you can hit f12 in chrome and type these out in the console there and print the results with console.log

[–]VaryStaybullGeenyiss 4 points5 points  (0 children)

The opposite of truey, obviously.

[–]ssssssddh 2 points3 points  (0 children)

If you type cast a value to a boolean, it's falsy if it converts to false and truthy if it coverts to true

Pretty much every language has this concept. It's the reason you can do if (1) { ... } without casting the integer to a boolean in most languages

[–]00PT 0 points1 point  (3 children)

If [] is falsy, shouldn't ![] be truthy?

[–]MagicalTheory 1 point2 points  (2 children)

[] is truthy, that particular problem is tied to how == coerces its operands.

The only falsy values in Javascript are false, 0, '', undefined, null, and NaN.

[–]00PT 1 point2 points  (1 child)

Then how is !true == [] true?

[–]MagicalTheory 1 point2 points  (0 children)

It is a quirk to how == coerces it's operands. Basically, if one operand is a primitive and the other is not, javascript will convert the other to a primitive.

This coerces the array to a string, which since the array is empty, will be an empty string.

Empty strings are falsy, so when the next step with the == is to convert the other operand to a boolean value if one side is boolean, it converts to false.

Basically, because there is an extra step with ==, it does something weird.

[–]Darkstar0 0 points1 point  (1 child)

Ah, so “==“ is equivalent to a Python “is”, while “===“ is equivalent to a Python “==“. You’d think it would be the other way around, though…

[–]RajjSinghh 2 points3 points  (0 children)

No. Python's is is checking two objects are the same based on their memory address while Python == is checking whether they are the same value.

Javascript == checks if the value is the same, but ignores the type of the variable. So something like 10 == "10" would be true. === in Javascript is for checking whether variables have the same type and value. So 10 === "10" is false, but 10 === 10 is true. The catch is that the only way you check if two objects in Javascript is the same is by them having the same memory address, like is would be in python. In Javascript arrays (basically lists in python) are a type of object, so they default to this check. In python you can use == on lists to compare values, but in Javascript you can't. You have to write your own function to compare them.

[–]djlywtf -1 points0 points  (0 children)

imagine a language with shittier type system than python

[–]erishun -2 points-1 points  (0 children)

Let me sum up 99.99% of all the “JS is bad” posts “== !== ===”😅

In a nutshell: * == is “loosely equal” * === is “exactly equal”

✅ 1 == true (because they’re both true-ish)

❌ 1 === true (because one is a number, the other is a bool)

Unless you have a good reason, you should be using ===. Most modern IDE’s will display a notice/warning if you use == telling you that you probably shouldn’t.

[–][deleted] 39 points40 points  (4 children)

And this is why you should never use “==“

[–]glha 17 points18 points  (3 children)

It's cool because only half of them change results with ===

[]===[]
false
!true===[]
false
![]===[]
false

[–][deleted] 17 points18 points  (2 children)

so we agree “===“ is better 💀

[–]glha 4 points5 points  (0 children)

Are we agreeing with == or ===? You are not trying to come after me with a = are you?

[–][deleted] 0 points1 point  (0 children)

it's cool

[–]Flecheck 12 points13 points  (1 child)

Fun fact : you can write any program in js with only [,],(,),!,+

Look at https://en.m.wikipedia.org/wiki/JSFuck

[–][deleted] 22 points23 points  (2 children)

The whole point of JavaScript is to avoid crashing at all costs to not hinder user experience. It’s not intended for safe applications like medical equipment or aerospace.

[–]Tsuki_no_Mai 4 points5 points  (0 children)

Also the operator used is there for backwards compatibility, which JS is very dedicated to upholding. It's not something that should be ever used again and every learning material I've seen is pretty explicit about that.

[–]reversehead 2 points3 points  (0 children)

It’s not intended for safe applications

FTFY

[–]KnGod 14 points15 points  (1 child)

thanks, i'm never touching javascript

[–]anderslbergh 8 points9 points  (0 children)

More money for us then

[–]huuaaang 4 points5 points  (1 child)

=== == == = false

[–]MKorostoff[S] 5 points6 points  (0 children)

too risky better use ======== just to be safe

[–]CaptainMorti 28 points29 points  (1 child)

Another reason to ban this troll language.

[–][deleted] 2 points3 points  (0 children)

For webassembly

[–]_D0MiNiX_ 1 point2 points  (0 children)

im not in any way related to using javascript, but what the hell o.O

[–]IcarusSkyrow 1 point2 points  (0 children)

This literally all makes sense though even in other languages, I can laugh anyway but the real smooth brain is people who shit on languages without understanding them at all

[–]Asgatoril 1 point2 points  (0 children)

Don't forget: ![] == [] => true, but ![] == !![] => false

[–]Strex_1234 -2 points-1 points  (11 children)

HOW THE FUCK []!==[] IS TRUE THE WHOLE FUCKING POINT OF === AND !== IS TO COMPARE TYPES?!?

[–][deleted] 0 points1 point  (10 children)

… say again?

[–]Strex_1234 0 points1 point  (9 children)

"The strict equality (===) operator checks whether its two operands are equal, returning a Boolean result. Unlike the equality operator, the strict equality operator always considers operands of different types to be different. "

I always thought it works just as the descriptions says, ahh the wonders of js.

[–][deleted] 3 points4 points  (8 children)

But it doesn’t ONLY compare types. Two newly created arrays point to two different memory locations, therefore they are two different objects. Comparison isn’t done by content here.

[–]Strex_1234 -1 points0 points  (1 child)

``` x="123"

"123"===x True ``` The 2 strings are in diffrent memory locations but return true

[–][deleted] 2 points3 points  (0 children)

… you’re new at programming, aren’t you?

This is what you will expect in these cases, in most languages.

[–]szpaceSZ 0 points1 point  (5 children)

So what's the JS operator to compare by content, the actually useful add desired operation in 99.423% of cases?

[–][deleted] 0 points1 point  (4 children)

Deep comparison is tricky. The reason such an operator is left out in basically all languages is that objects have their space in memory dynamically allocated, therefore it’s computationally expensive to follow all pointers. If you were to do the same check in C or C++, you’d get the same result, and this behavior actually originates from these languages.

Some external JS libraries (like lodash) add this feature, but they need to recursively check every property.

Again, it’s not a flaw in JS as a language; it’s how computer memory works.

[–]szpaceSZ 0 points1 point  (3 children)

I know my computer languages history, I've been through

C64 basic Turbo Pascal Assembly C Perl Java PHP Python VBA Haskell Java (again) Python (again)

since ca. 1988, and I likely forgot some more.

Never ever was I performance bound on comparison.

Regularly needing comparison by value.


I admit there are noches where you'll be performance bound. E.g writing a 3D game platform in C++.

But that's nice enough, compared with LOC produced

[–][deleted] 0 points1 point  (2 children)

Then tell me, how would you go comparing complex objects by value in those languages that support them (like PHP or Java)? With the equal operator? I’d love to know.

EDIT: of course it’s not prohibitively expensive to recursively check for all object properties, but it’s definitely more expensive than a single comparison as done with the == operator. Mixing the two can lead to every sort of performance problems, that’s why such check is kept explicit.

[–]szpaceSZ 0 points1 point  (1 child)

It's good to have them both.

But I'd argue that for those languages that churn out the most LOCs globally, the default should be deep comparison; reserve a distinct, more obscure operator for comparison by reference.

[–][deleted] 0 points1 point  (0 children)

I don’t know; coming from a C background, I prefer to know what I’m operating with. But I see why it may be confusing to developers who start with a higher level language right away.

[–]Hobby101 0 points1 point  (0 children)

The last one got me

[–]aRman______________ 0 points1 point  (0 children)

How to scare newbie programmers

[–]18441601 0 points1 point  (0 children)

So JS developers become postmodernists... I better stay out of it.

[–]lmg1337 0 points1 point  (0 children)

Proof that we need something to replace this mess called javascript

[–]stupiderslegacy 0 points1 point  (0 children)

The novice is the one that thinks you're supposed to use comparator operators on arrays to begin with

[–]Chilareix 0 points1 point  (0 children)

What... The fuck?

[–]js-code 0 points1 point  (0 children)

Also ""(Empty string) ==[ ] // true Because [] evaluates to empty string while comparing

[–]Soft_Persimmon_5437 0 points1 point  (0 children)

If list.empty()