JavaScript's Infamous Octal Number Quirk
Description
This is a two-panel meme that perfectly captures a frustrating and non-intuitive aspect of JavaScript. The top panel shows a code editor with a JavaScript file named 'index.js'. The code consists of two lines: `console.log(018 == '018');` and `console.log(017 == '017');`. The terminal output below shows 'true' for the first line and 'false' for the second. The bottom panel features a still from the game Team Fortress 2, with two characters laughing hysterically, captioned with 'JavaScript Moment'. The technical humor lies in JavaScript's legacy handling of octal (base-8) literals. A number starting with a zero (like 017) is treated as octal. Since octal only uses digits 0-7, `017` is valid octal for the decimal number 15. However, `018` is an invalid octal number, so JavaScript silently treats it as the decimal number 18. When using the loose equality `==` operator, `18 == '018'` coerces to `18 == 18` (true), while `15 == '017'` coerces to `15 == 17` (false). This counter-intuitive behavior is a classic 'gotcha' that leads to bugs and developer frustration
Comments
63Comment deleted
JavaScript's loose equality is the reason code reviews exist. It's the only place where `017` being unequal to `'017'` is somehow logical
JavaScript Annex B: 017 time-travels to octal 15, 018 gets deported back to decimal, and your diff suddenly looks like a PDP-11 permissions audit
After 20 years in the industry, you'd think we'd all remember to use strict mode by now - but no, we're still discovering that JavaScript treats 018 as decimal because even octal numbers have standards, while 017 happily becomes 15 in base-10. It's like finding out your production config parser has been silently misinterpreting UNIX file permissions for years
Ah yes, the classic '018 == "018"' returns true but '017 == "017"' returns false - because JavaScript sees that leading zero on 017 and thinks "ah, octal!" converting it to decimal 15, while 018 is an invalid octal (no 8 in base-8) so it just shrugs and treats it as decimal 18. This is why we have 'use strict' and ESLint rules, folks. Nothing says 'battle-tested language design' quite like having to explicitly disable footguns from 1995
In JS, leading zeros are a time machine: 017 is octal 15, 018 is decimal, and '==' smiles through it - use strict modules or stop zero-padding like it’s 1995
Loose equality is fine - until a single leading zero from a CSV turns billing into base‑8 and on‑call into exponential backoff
JS octals: valid only sans '8', because who needs consistent parsing when you have history to honor?
still better than python Comment deleted
Have you ever seen Python moments like that? Comment deleted
ahahaa so funny, silly python developers😂 Comment deleted
how often you write shitty code like that? Comment deleted
Bruh That's literally gh repo about python moments https://github.com/satwikkansal/wtfpython Comment deleted
Try using both spaces and tabs Comment deleted
That's one way to start a flamewar... Comment deleted
Why first one is true and second one is false? Comment deleted
Probably, because of leading zero second is treated like it is base 8 Comment deleted
017 (oct) = 15 (dec) 018 = 18 Comment deleted
I think the weird part is that "017" is implicitly converted to 17 instead of 15 Comment deleted
ig these conversions aren't considered thoroughly. For binaries and hexadecimals it works well. parseInt however recognizes only hexadecimals Comment deleted
Why would base 8 literal with 8 in it be treated as anything other than error... This language is cancer Comment deleted
2.3.1 An integer constant is a sequence of digits. An integer is taken to be octal if it begins with 0, decimal otherwise. The digits 8 and 9 have octal value 10 and 11 respectively. Comment deleted
in old C it wasn't an error either Comment deleted
Day ruined Comment deleted
Surprised? Comment deleted
Yeah, a little bit. I would've been less surprised if 018 somehow did something unexpected in modern c++ with all of its bloat. The more you know Comment deleted
C is the same junks as JS, it was called "assembly for lazy people". Maybe it is better now but doubt it - CVEs still come in every day Comment deleted
I think that in terms of security any maintained language that gets its vulnerabilities fixed in timely manner is as good as any other. For me C is not the same junks as JS, but it is an opinion. In the end of the day it all comes down to personal preference and the problem that needs to be solved. Comment deleted
A lot of vulnerabilities should not have appeared in the first place. A little bounds check by compiler, a little type safety would do. But no, people still think it is all "makes code slow" (in places where this doesn't matter) and compile with no checks and etc. Comment deleted
018 isn't valid octal tho 😭😭😭 it should reject it with an error Comment deleted
018 is not a valid octal number and javscript will treat it as a decimal number as a fallback. better would be to maybe throw an error I suppose Comment deleted
https://www.youtube.com/watch?v=FhNwLvCYlY4 Comment deleted
octal vs decimal? Comment deleted
455 257 weekly installations <3 Comment deleted
let’s pretend static comparison doesn’t exist Comment deleted
омагааах Comment deleted
Something was changed in the V8 a couple years ago, if I am not mistaken. Where did you execute it? Comment deleted
It's not V8, it's == vs === Comment deleted
Oh, I see Comment deleted
It still baffles me that so many programming languages use line breaks [as end of statement] to tokenize the code. 🤓 Comment deleted
Your cryptic message looks like some shell script bomb. Comment deleted
this is actually intended to be like that, i don't see the problem with this Comment deleted
Programming languages for pussies, use runes Comment deleted
I would like to hear more 👀 Comment deleted
why? Comment deleted
Classic "I have no fucking clue how my programming language works so I'll make fun of it" moment Comment deleted
because of more syntactic noise? nonsense. you just got used to it. let me bring an example Comment deleted
what is simpler to read? Comment deleted
foo x = let s = sin x c = cos x in 2 * s * c Comment deleted
or Comment deleted
foo x = let { s = sin x; c = cos x; } in 2 * s * c Comment deleted
if your code is small enough, then all those curly and round braces are just noise. imagine it to be folded like multiple times, then instead of a couple of lines of information we will have a lot of curly braces that get opened and closed. another example what is easier to read? f1(f2(f3(f4(x)))) or f1 . f2 . f3 . f4 x Comment deleted
it's about, the thing, that with more experience you need less syntax for short concise solutions Comment deleted
why? Comment deleted
it has more syntax you don't need to understand either way. and formatting is more machine readable rather than human readable. Comment deleted
it's about using right tools for right tasks. i know there are huge monolith python projects out there and its a pain to work with them. but if you just need a small script like <1000lines. it's even easier to comprehend if it has less syntactic noise. Comment deleted
for composition too Comment deleted
yeah. people just take Java and write 10000 lines of SOLID code, while the same fits in a mere 200 lines of SQL script Comment deleted
for example, how to reduce the amount of lines of code by more than 10 times? throw away ORM. even in python SQL code like: CREATE TABLE id_table(id INTEGER PRIMARY KEY); a minimal table. requires this much of code from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy.orm import DeclarativeBase class Base(DeclarativeBase): pass class IdTable(Base): __tablename__ = "id_table" id = Column(Integer, primary_key=True) Comment deleted
and it even doesn't provide a proper type hints. I'm really unable to comprehend the advantage. it doesn't provide even type hinting it requires different code for different data bases... so it has all the disadvantages of the pure sql solution, but the more complex it gets, the harder it is to use the ORM compared to pure SQL. my last experience with it was to drop the development of the data model after 250 lines and 3 days of complicated OOP code. and then solve the task in 16 lines and a couple of minutes of declarative code. Comment deleted
JS was initially designed to execute any crap, any ravings of any madman at any cost. All subsequent evolution of this monstrosity is no more than futile attempts to formalize it ang ram some logical explanations of its behavior down our throats. Comment deleted
still better than excel Comment deleted
Wow, this post definitely caught my eye. Cant wait to see more from you. 😉 Comment deleted
not really js moment. C did this too back in a day. Comment deleted