11. 11
Numbers in JavaScript
● Follow the IEEE 754 standard (floating point
numbers)
● The same as in other programming languages (float,
double, e.g. in C, C++, C#, Rust, go)
● Non-power-of-2 fractions have limited precision
12. 12
Numbers in JavaScript
● Follow the IEEE 754 standard (floating point
numbers)
● The same as in other programming languages (float,
double, e.g. in C, C++, C#, Rust, go)
● Non-power-of-2 fractions have limited precision
13. 13
Numbers in JavaScript
● Follow the IEEE 754 standard (floating point
numbers)
● The same as in other programming languages (float,
double, e.g. in C, C++, C#, Rust, go)
● Non-power-of-2 fractions have limited precision
0.25 = ¼ - power of 2
14. 14
Numbers in JavaScript
● Follow the IEEE 754 standard (floating point
numbers)
● The same as in other programming languages (float,
double, e.g. in C, C++, C#, Rust, go)
● Non-power-of-2 fractions have limited precision
● Same behavior as in other languages
15. 15
Doubles in C++
int main()
{
cout << 0.1 + 0.2; // 0.3
return 0;
}
int main()
{
printf("%f", 0.1 + 0.2); // 0.300000
return 0;
}
16. 16
Doubles in C++
int main()
{
double result = 0.1 + 0.2;
cout << (result == 0.3); // 0
return 0;
}
int main()
{
printf("%.17f", 0.1 + 0.2);
// 0.30000000000000004
return 0;
}
17. 17
Special IEEE 754 values
● Non-number values have their own representation
○ NaN (Not a Number) - invalid operation, e.g. converting an object to a number
○ Positive/negative infinity - division by 0 or the value was too large
● Present in the specification
● https://en.wikipedia.org/wiki/IEEE_754-1985#Representation_of_non-numbers
● Consistent across all languages that use IEEE 754
27. 27
Comparing NaNs in C++
int main()
{
double result = sqrt(-5);
cout << (result == result); // false
return 0;
}
Always false (not only
in JS)
Specified in IEEE 754
28. 28
Checking if a value is NaN
console.log(isNaN(NaN));
console.log(isNaN({}));
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
29. 29
Checking if a value is NaN
console.log(isNaN(NaN)); // true
console.log(isNaN({}));
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
30. 30
Checking if a value is NaN
console.log(isNaN(NaN)); // true
console.log(isNaN({})); // true
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
31. 31
Checking if a value is NaN
console.log(isNaN(NaN)); // true
console.log(isNaN({})); // true
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
32. 32
Checking if a value is precisely NaN
console.log(Number.isNaN({})); // false
// isNaN(x) = Number.isNaN(Number(x))
console.log(isNaN({})); // true
Number.isNaN (ES6)
https://developer.mozilla.org/
en-US/docs/Web/JavaScript/
Reference/Global_Objects/Nu
mber/isNaN
http://www.ecma-international.org/ecma-262/6.0/#sec-number.isnan
35. 35
Matching multiple times
const pattern = /a+b+/g;
const text =
'aabbababaaaaaaabbbbbb' ;
while (true) {
const match = pattern.exec(text);
if (match === null) {
break;
}
console.log(match[0]);
}
36. 36
Matching multiple times
const pattern = /a+b+/g;
const text =
'aabbababaaaaaaabbbbbb' ;
while (true) {
const match = pattern.exec(text);
if (match === null) {
break;
}
console.log(match[0]);
}
37. 37
State saved in `lastIndex`
const pattern = /a+b+/g;
const text =
'aabbababaaaaaaabbbbbb' ;
while (true) {
const match = pattern.exec(text);
if (match === null) {
break;
}
console.log(match[0], pattern.lastIndex);
}
https://developer.mozilla.org/en-U
S/docs/Web/JavaScript/Reference
/Global_Objects/RegExp/lastIndex
38. 38
State saved in `lastIndex`
const pattern = /a+b+/g;
const text =
'aabbababaaaaaaabbbbbb' ;
while (true) {
const match = pattern.exec(text);
if (match === null) {
break;
}
console.log(match[0], pattern.lastIndex);
}
39. 39
Change from where matching starts
const pattern = /a+b+/gi;
const text = 'aabbabABaaaaaaabbbbbb';
// 0123456789
pattern.lastIndex = 5;
40. 40
Change from where matching starts
const pattern = /a+b+/gi;
const text = 'aabbabABaaaaaaabbbbbb';
// 0123456789
pattern.lastIndex = 5;
console.log(pattern.exec(text)[0], pattern.lastIndex); // AB, 8
41. 41
Be careful with the global flag
const pattern = /Java/g;
const text1 = 'JavaScript is the best programming language';
pattern.exec(text1);
const text2 = 'Java is the best programming language';
pattern.exec(text2);
42. 42
Be careful with the global flag
const pattern = /Java/g;
const text1 = 'JavaScript is the best programming language';
pattern.exec(text1);
const text2 = 'Java is the best programming language';
pattern.exec(text2);
45. 45
Variable scope - const, let
function foo() {
if (true) {
const a = 1;
let b = 2;
}
console.log(a, b);
}
foo();
46. 46
Variable scope - const, let
function foo() {
if (true) {
const a = 1;
let b = 2;
}
console.log(a, b); // ReferenceError: a is not defined
}
foo();
47. 47
Variable scope - var
function foo() {
if (true) {
var a = 10;
}
console.log(a);
}
foo();
48. 48
Variable scope - var
function foo() {
if (true) {
var a = 10;
}
console.log(a); // 10
}
foo();
49. 49
Variable scope - var
function foo() {
if (true) {
var a = 10;
}
console.log(a); // 10
}
foo();
53. 53
Hoisting explained
function foo() {
var a;
console.log(a);
a = 0;
console.log(a);
}
foo();
https://developer.mozilla.org/en-US/docs
/Glossary/Hoisting
function foo() {
console.log(a);
var a = 0;
console.log(a);
}
foo();
54. 54
Hoisting explained
function foo() {
var a;
console.log(a); // undefined
a = 0;
console.log(a); // 0
}
foo();
https://developer.mozilla.org/en-US/docs
/Glossary/Hoisting
function foo() {
console.log(a);
var a = 0;
console.log(a);
}
foo();
55. 55
Do not do this at home
function foo() {
a = 1;
console.log(a); // 1
var a = 0;
console.log(a); // 0
}
foo();
59. 59
IIFE to the rescue
IIFE - Immediately Invoked Function Expression
(function() {
var bar = 1;
console.log(window.bar); // undefined
})();
https://developer.mozilla.org/en-US
/docs/Glossary/IIFE
60. 60
… or use `let` and `const`
const baz = 1;
let abc = 2;
console.log(window.baz);
console.log(window.abc);
77. 77
Or (||) operator - lazy evaluation
function getValue() {
console.log('This will not run, because 5 is truthy');
return 10;
}
console.log(5 || getValue());
Operands are evaluated lazily
78. 78
Or (||) operator - default function parameter
function foo(arg) {
arg = arg || 10;
console.log(arg);
}
foo(1);
foo(5);
foo();
foo(0);
79. 79
Or (||) operator - default function parameter
function foo(arg) {
arg = arg || 10;
console.log(arg);
}
foo(1); // 1
foo(5); // 5
foo(); // 10
foo(0);
88. 88
Tuples in JS?
const tuple = (1, 2, 3);
console.log(tuple); // 3
Similar behavior in other
languages, e.g. C, C++
89. 89
Comma operator in C
int main()
{
int x = 10, y = 15;
printf("%d", (x, y)); // 15
return 0;
}
90. 90
Comma operator
const doMultipleThings = (service) =>
(
service.doA(),
service.doB(),
service.doC()
);
Evaluates the expression on the left, returns the expression on the right
const boringDoMultipleThings =
(service) => {
service.doA();
service.doB();
return service.doC();
}
91. 91
A side note on ASI
What happens if you don’t like semicolons?
const boringDoMultipleThings =
(service) => {
service.doA();
return service.doC();
}
92. 92
A side note on ASI
What happens if you don’t like semicolons?
const boringDoMultipleThings =
(service) => {
service.doA();
return service.doC();
}
93. 93
A side note on ASI
What happens if you do not like semicolons?
const boringDoMultipleThings =
(service) => {
service.doA()
return service.doC()
}
94. 94
A side note on ASI
const boringDoMultipleThings =
(service) => {
service.doA()
return
service.doC()
}
What happens if you don’t like semicolons?
95. 95
A side note on ASI
const boringDoMultipleThings =
(service) => {
service.doA()
return
service.doC()
}
boringDoMultipleThings()
What happens if you don’t like semicolons?
96. 96
A side note on ASI
const boringDoMultipleThings =
(service) => {
service.doA()
return
service.doC()
}
boringDoMultipleThings()
Not executed
What happens if you don’t like semicolons?
97. 97
A side note on ASI
ASI - Automatic Semicolon Insertion
const boringDoMultipleThings =
(service) => {
service.doA()
return
service.doC()
}
boringDoMultipleThings()
const boringDoMultipleThings =
(service) => {
service.doA();
return;
service.doC();
}
boringDoMultipleThings();
98. 98
A side note on ASI
ASI - Automatic Semicolon Insertion
const boringDoMultipleThings =
(service) => {
service.doA()
return
service.doC()
}
boringDoMultipleThings()
const boringDoMultipleThings =
(service) => {
service.doA();
return;
service.doC();
}
boringDoMultipleThings();
Use a linter
101. 101
try … finally without catch
function throwWithNoReturn() {
try {
throw new Error();
} finally {
}
}
throwWithNoReturn();
102. 102
try … finally without catch
function throwWithNoReturn() {
try {
throw new Error();
} finally {
}
}
throwWithNoReturn();
103. 103
try … finally - return in finally
function throwAndReturnInFinally() {
try {
throw new Error();
} finally {
return 'I will be returned';
}
}
throwAndReturnInFinally();
104. 104
try … finally - return in finally
function throwAndReturnInFinally() {
try {
throw new Error();
} finally {
return 'I will be returned';
}
}
throwAndReturnInFinally();
105. 105
try … finally - return in finally
function throwAndReturnInFinally() {
try {
throw new Error();
} finally {
return 'I will be returned';
}
}
throwAndReturnInFinally();
Where is the error?
106. 106
try … finally - returning
function returnsInTryAndFinally() {
try {
return 'I want to be returned';
} finally {
return "No, you won't";
}
}
returnsInTryAndFinally();
107. 107
try … finally - returning
function returnsInTryAndFinally() {
try {
return 'I want to be returned';
} finally {
return "No, you won't";
}
}
returnsInTryAndFinally();
108. 108
try … finally - returning
function returnsInTryAndFinally() {
try {
return 'I want to be returned';
} finally {
return "No, you won't";
}
}
returnsInTryAndFinally();
124. 124
Variadic functions
Variadic - take an arbitrary number of arguments (e.g. console.log)
sum(1, 2); // 3
sum(1, 2, 3, 4, 5, 6, 7); // 28
125. 125
Variadic functions in ES6 (rest syntax)
function es6Sum(...args) {
return args.reduce((sum, x) => sum + x, 0);
}
126. 126
Variadic functions in ES5
function es5Sum() {
let result = 0;
for (let i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
}
127. 127
arguments - not a valid array
function invalidUse() {
arguments.forEach(x => {
// ...
});
}
131. 131
“Inheritance” in JavaScript
● Prototypal inheritance (not classical inheritance)
● Each object has a [[Prototype]] (another object or null)
● Prototype chain - multiple objects connected via prototype
● During property lookup, either:
○ Property exists on the object itself
○ The prototype chain is traversed to find the property
● Can be confusing for programmers of other languages
● Dynamic - can be manipulated at runtime
Animal.prototype
Object.prototype
null
cat dog
132. 132
Custom merge
function merge(dest, src) {
for (let property in src) {
if (
typeof dest[property] === 'object' &&
typeof src[property] === 'object'
) {
merge(dest[property], src[property]);
} else {
dest[property] = src[property];
}
}
}
145. 145
with statement
function extractValuesFromSubarrays (array, indexOf) {
with (array) {
return map(subArray => subArray[indexOf]);
}
}
const array = [[1, 2, 3], [4, 5]];
extractValuesFromSubarrays (array, 1); // [undefined, undefined]
Array.prototype.indexOf,
not the indexOf parameter
146. 146
with statement
● Cannot be optimized by the compiler (depends on the runtime value)
● Not recommended
● Will throw an error in strict mode
More information:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Sta
tements/with
152. 152
Other fun symbols
Well-known symbols:
● Symbol.iterator (used by for...of)
● Symbol.asyncIterator (used by for await...of)
● Symbol.hasInstance (used by instanceof)
● Symbol.toPrimitive
https://developer.mozilla.org/en-US/docs/Web/JavaScript
/Reference/Global_Objects/Symbol
Introduced in ES6
154. 154
Summary
● Not all quirks are JavaScript-only (comma operator, IEEE 754)
● New features make it easier to avoid pitfalls (arrow functions, const,
let)
● Some features are very different than in other languages (prototypal
inheritance), so watch out