Programming with AI
ENRU
9.1

Reading JavaScript

six places where Python intuition breaks

What it is

JavaScript resembles Python just closely enough to mislead. Loops, functions and conditions look familiar — and then the code does something else, and it isn't clear why.

This article covers six places where intuition lets you down. Everything below is real node output, not a retelling of the documentation.

What it looks like in code

1. Sorting numbers doesn't sort numbers

[10, 9, 1, 100].sort()
measured
[ 1, 10, 100, 9 ]

By default sort turns the elements into strings and compares them as text. Numbers need a comparison function:

[10, 9, 1, 100].sort((a, b) => a - b)     // [ 1, 9, 10, 100 ]

The mistake is silent: with numbers from 1 to 9 you don't notice it; with two digits it breaks.

2. Two kinds of equality

measured
'1' ==  1   ->  true
'1' === 1   ->  false
null ==  undefined   ->  true
null === undefined   ->  false

== converts types before comparing, === doesn't. The rule is simple: always ===. The one justified exception is x == null, which checks for null and undefined in a single go.

3. Truthiness is not what you're used to

measured
[]        -> truthy      (in Python an empty list is false!)
{}        -> truthy
""        -> falsy
"0"       -> truthy
0         -> falsy
NaN       -> falsy
null      -> falsy
undefined -> falsy

The first line breaks more code than any other. The "are there any items" check written as if (items) is always true in JavaScript, even for an empty array. It has to be if (items.length).

4. Plus concatenates, minus subtracts

measured
1 + '1'   ->  '11'      (joined the strings)
1 - '1'   ->  0         (converted to numbers)

Hence the classic: the data arrived from a form or from JSON as strings, and instead of a sum you get a join. '10' + 5 gives '105'.

5. Two kinds of "nothing"

What it means
undefinedthere was no value: no such key, the function returned nothing
nullthere is a value, and it is "nothing"

Reaching for a key that doesn't exist doesn't fail:

measured
user.email               ->  undefined
user.email?.length       ->  undefined
user.email ?? 'not set'  ->  'not set'

This is the opposite of Python, where that gives a KeyError. Convenient and dangerous at once: the mistake doesn't announce itself, it surfaces later as Cannot read properties of undefined (article 8.4).

Two operators you will meet constantly:

  • ?. — "if the left side isn't null/undefined, keep going, otherwise return undefined";
  • ?? — "take the left one, and if it is null/undefined, take the right one".

?? differs from || in not treating 0 and "" as emptiness. For numbers that is decisive: temp || 20 turns zero degrees into twenty, temp ?? 20 doesn't.

6. const doesn't make an object immutable

const cities = ["Oslo"];
cities.push("Bergen");      // allowed
cities = [];                // not allowed

const forbids reassigning the variable, not changing the contents. The same thing as references in Python (article 2.4).

What to tell the AI

Prompt
Rewrite this code with strict comparisons: === everywhere
instead of ==, array checks through .length, ?? instead of ||
where the value may be 0 or an empty string.
Don't change the behaviour.
Prompt
This code came from Python. What will behave differently here
because of JavaScript's quirks? Just the list of differences.
Prompt
The numbers arrive from JSON as strings. Where in this code
could a concatenation happen instead of an addition?

What to look for

== in generated code. It should almost always be ===.

sort() without a comparison function on numbers.

if (array) instead of if (array.length). The condition is always true.

|| for default values. Breaks on 0 and "". You want ??.

var. An outdated declaration with surprising scope. New code uses only let and const (article 3.1, reason 3).

Numbers from strings without conversion. Number(x) or parseInt(x, 10) — and always with the base 10.

Cheat sheet

  • sort() sorts as strings by default: [1, 10, 100, 9].

  • Always ===. The exception is x == null for both emptinesses at once.

  • An empty array is truthy. Check .length.

  • + with a string concatenates, - converts to numbers.

  • ?. is safe access, ?? is a default value (not to be confused with ||).

  • const forbids reassignment, not mutation.