JavaScript 01 · JavaScript in general
Variables, types and operators
const and let, numbers and text, type conversion, === vs. == and useful string methods.
Loading lesson…
JavaScript 01 · JavaScript in general
const and let, numbers and text, type conversion, === vs. == and useful string methods.
Loading lesson…
People learning React often find that it isn't React that trips them up, but the JavaScript around it. React itself is just a handful of functions – everything else you write in a component is plain JavaScript.
It's like cooking from recipes. Recipes (React) are quick to learn – as long as you can chop, fry and weigh (JavaScript). If you can't chop, every recipe is a struggle. So the first eight lessons are a kind of knife skills course: general JavaScript, no React. The last two lessons of this part then show how these skills are used in React.
A variable is a named box for a value. In modern JavaScript you create one with two keywords:
const name = 'Anna' // const = the box can't be refilledlet count = 0 // let = you can put another value in the box latercount = count + 1 // ✅ let can be reassignedcount += 1 // ✅ the same, shortercount++ // ✅ even shorter (+1)name = 'Peter' // ❌ TypeError: Assignment to constant variable.
| const | let | var | |
|---|---|---|---|
| Can be reassigned? | no | yes | yes |
| Valid in | the block { … } | the block { … } | the whole function (confusing) |
| Use it? | yes, the default choice | when the value changes | no, it's outdated |
A variable only exists inside the curly braces { … } it was created in. Outside, nobody knows about it:
const price = 100if (price > 50) {const discount = 10 // only exists inside this blockconsole.log(price - discount) // 90 – you can see outer variables inside too}console.log(discount) // ❌ ReferenceError: discount is not defined
userName, totalPrice, isLoggedIn.is, has, can, should: isOpen, hasError.users), a single item in the singular (user).getUser, formatPrice, handleClick.Every value in JavaScript has a type. Primitive types are simple values, everything else is an object:
| Type | Examples | typeof returns |
|---|---|---|
| string (text) | 'hello', "hello", `hello` | 'string' |
| number | 42, 3.14, -1, NaN, Infinity | 'number' |
| boolean | true, false | 'boolean' |
| undefined | "no value has been set yet" | 'undefined' |
| null | "intentionally empty" | 'object' ⚠️ a historical bug |
| object | { name: 'Anna' }, [1, 2], new Date() | 'object' |
| function | () => {} | 'function' |
typeof 'hello' // 'string'typeof 42 // 'number'typeof true // 'boolean'typeof undefined // 'undefined'typeof { a: 1 } // 'object'typeof [1, 2] // 'object' – an array is an object too!typeof null // 'object' – a bug from 1995 that never went awayArray.isArray([1, 2]) // true – the right way to recognise an arrayvalue === null // the right way to recognise null
JavaScript has a single type, number, for both whole and decimal numbers.
10 + 3 // 1310 - 3 // 710 * 3 // 3010 / 3 // 3.333333333333333510 % 3 // 1 – the remainder after division (modulo)2 ** 10 // 1024 – powerMath.round(2.5) // 3 – roundsMath.floor(2.9) // 2 – downMath.ceil(2.1) // 3 – upMath.trunc(-2.9) // -2 – cuts off the decimal partMath.abs(-5) // 5Math.min(4, 1, 9) // 1Math.max(4, 1, 9) // 9Math.random() // a random number from 0 (inclusive) to 1 (exclusive)
7 % 2 === 1 // an odd number8 % 2 === 0 // an even numberconst seconds = 187Math.floor(seconds / 60) // 3 – whole minutesseconds % 60 // 7 – the remaining seconds → "3:07"index % 3 // 0, 1, 2, 0, 1, 2… – taking turns in a cycle (colours, say)
0.1 + 0.2 // 0.30000000000000004 😱0.1 + 0.2 === 0.3 // false(0.1 + 0.2).toFixed(2) // '0.30' – CAREFUL, returns TEXTMath.round((0.1 + 0.2) * 100) / 100 // 0.3 – a number rounded to 2 places
A computer stores numbers in binary and can't write 0.1 in it exactly – just as we can't write 1/3 exactly as a decimal. That's why money is often counted in cents (whole numbers) and converted to dollars or euros only when it's displayed.
Number('hello') // NaN0 / 0 // NaNNaN === NaN // false – NaN isn't even equal to itself!Number.isNaN(NaN) // true – the only reliable test10 / 0 // Infinity (not an error)
You can write text in single '…', double "…" or back `…` quotes. Backticks have a superpower: you can put a value inside.
const name = 'Anna'const count = 3'Hello, ' + name + '! You have ' + count + ' messages.' // the old way – easy to forget a space`Hello, ${name}! You have ${count} messages.` // template – ${…} inserts the value`Total: ${count * 12} USD` // any expression can go inside ${…}`Status: ${count > 0 ? 'you have some' : 'empty'}`const html = `<ul><li>A template can span several lines</li></ul>`
Strings can't be changed – every method returns a new text and leaves the original alone.
const text = ' Hello World 'text.length // 15 – the number of characters (spaces included)text.trim() // 'Hello World' – without spaces at the endstext.toUpperCase() // ' HELLO WORLD 'text.toLowerCase() // ' hello world 'const s = 'Hello World's[0] // 'H' – the character at position 0 (counting starts at zero!)s.at(-1) // 'd' – the last characters.includes('World') // trues.startsWith('Hello') // trues.endsWith('!') // falses.indexOf('W') // 6 – where it starts; -1 when not founds.slice(0, 5) // 'Hello' – from position 0 to 5 (5 not included)s.slice(-5) // 'World' – the last 5 characterss.replace('World', 'Anna') // 'Hello Anna' – replaces the FIRST occurrence'a-b-c'.replaceAll('-', '/') // 'a/b/c' – replaces all of them'Anna Smith'.split(' ') // ['Anna', 'Smith'] – splits into an array['a', 'b', 'c'].join(', ') // 'a, b, c' – the opposite: joins an array into text'7'.padStart(2, '0') // '07' – pads on the left to length 2'ha'.repeat(3) // 'hahaha'
'a' < 'b' // true – compares by character codes'Z' < 'a' // true 😕 capital letters have smaller codes'é' > 'f' // true 😕 accented letters come after the English alphabet'é'.localeCompare('f', 'fr') // -1 – "é comes before f" according to French ✅'Anna'.toLowerCase() === 'anna' // comparison that ignores letter case
Everything a user types into a form arrives as text. Even when they type "42". If you want to calculate with it, you have to convert it:
Number('42') // 42Number('3.14') // 3.14Number('3,14') // NaN – a comma isn't a decimal point!Number('') // 0 – careful, empty text is zeroNumber(' 7 ') // 7 – spaces at the ends don't matterNumber('12px') // NaNparseInt('12px') // 12 – reads digits from the left as long as it canparseFloat('3.5kg') // 3.5parseInt('3.9') // 3 – only the whole partString(42) // '42'(42).toString() // '42'42 + '' // '42' – works, but String() is easier to readBoolean('hello') // trueBoolean('') // false!!'hello' // true – a double negation is a shortcut for Boolean()
When JavaScript gets an unexpected type, it tries to convert it on its own. The results can be surprising:
'5' + 3 // '53' – plus with text JOINS texts'5' - 3 // 2 – minus only works with numbers, so it converts the text'5' * '2' // 10true + 1 // 2[] + [] // '''10' > '9' // false 😱 compares texts character by character: '1' < '9'10 > 9 // true
What you see: A text field and, below it, what different conversions make of its contents. This is exactly how values arrive from forms – always as text.
Try it:
text + 1 gives '421' (joined texts), but text * 1 gives the number 42 – multiplication converts the text to a number.Number returns NaN, parseFloat just 3. Only replacing the comma with a dot helps.Number gives up, parseInt reads 12.Number('') is 0, but Boolean('') is false. And '' == 0 is even true.The takeaway: Always convert form text yourself and check it with Number.isNaN. Relying on automatic conversion is a road to bugs.
Loading the interactive part…
Two equals signs (==) convert types before comparing, following complicated rules. Three equals signs (===) compare both the type and the value – no surprises.
| Expression | == (loose) | === (strict) |
|---|---|---|
5 vs '5' | true | false |
0 vs '' | true | false |
0 vs false | true | false |
null vs undefined | true | false |
NaN vs NaN | false | false |
5 === 5 // true5 === '5' // false – a different type5 !== '5' // true – "not equal" in the strict versionage >= 18 // greater than or equalage < 65 && age >= 18 // and at the same time (more in the lesson on conditions)
Two really short functions to warm up: a greeting with a name and double a number. What exactly they should return is in the comments in the code.
Task is in the comments in the code below – at the top of the file and at the places marked TODO.
Loading the interactive part…
Six small functions for working with numbers and text – exactly the kind you need when processing forms. Functions come in the next lesson, so they are prepared for you: you only change the places with TODO and the comment next to them says what value the line should produce. Under the editor you'll see which functions already work.
Task is in the comments in the code below – at the top of the file and at the places marked TODO.
Loading the interactive part…
const everywhere, let only when you reassign the value, var never. A variable is valid in its block { … }.Array.isArray.0.1 + 0.2). Round with Math.round(x * 100) / 100, toFixed returns text.`…${x}…` instead of joining with plus. String methods return a new text.Number() and watch out for NaN.===, never ==.