Jeremy Fairbank
February 23, 2017
260

# DevNexus 2017: Functional Programming Basics in ES6

## Jeremy Fairbank

February 23, 2017

## Transcript

1. FUNCTIONAL
PROGRAMMING
Jeremy Fairbank
blog.jeremyfairbank.com
@elpapapollo / jfairbank
BASICS IN ES6

2. sigient.com

3. ¯\_(ϑ)_/¯
WHAT IS FUNCTIONAL
PROGRAMMING?

4. ¯\_(ϑ)_/¯
WHY FUNCTIONAL
PROGRAMMING?

5. Domain to Range

6. Domain Range

7. CALCULUS

8. PRINCIPLES

9. PURE & DECLARATIVE
PREDICTABLE

10. IMMUTABLE STATE
SAFE

11. FIRST CLASS STATE
TRANSPARENT

12. COMPOSABLE FIRST
CLASS CLOSURES
MODULAR

13. ES2015
(ES6)

14. let age = 10;
age = 11;
const name = 'Tucker';
name = 'Sally';
All good
Syntax error

15. const add = (x, y) => {
return x + y;
};
const identity = x => x;

16. const add = (x, y) => {
return x + y;
};
const identity = x => x;

17. const add = (x, y) => {
return x + y;
};
const identity = x => x;

18. const add = (x, y) => {
return x + y;
};
const identity = x => x;

19. const add = (x, y) => {
return x + y;
};
const identity = x => x;

20. const add = (x, y) => {
return x + y;
};
const identity = x => x;

21. const array = (...elements) => {
return elements;
};
array(1, 2, 3); // [1, 2, 3]

22. const array = (...elements) => {
return elements;
};
array(1, 2, 3); // [1, 2, 3]

23. const array = (...elements) => {
return elements;
};
array(1, 2, 3); // [1, 2, 3]

24. const array = (...elements) => {
return elements;
};
array(1, 2, 3); // [1, 2, 3]

25. const log = (...args) => {
console.log(...args);
};
log('Hello', 'DevNexus');
// Hello DevNexus

26. const log = (...args) => {
console.log(...args);
};
log('Hello', 'DevNexus');
// Hello DevNexus

27. const langs = [
'JavaScript',
'Elm',
];
const [js, ...rest] = langs;
js === 'JavaScript';
rest[0] === 'Elm';

28. const langs = [
'JavaScript',
'Elm',
];
const [js, ...rest] = langs;
js === 'JavaScript';
rest[0] === 'Elm';

29. const langs = [
'JavaScript',
'Elm',
];
const [js, ...rest] = langs;
js === 'JavaScript';
rest[0] === 'Elm';

30. const langs = [
'JavaScript',
'Elm',
];
const [js, ...rest] = langs;
js === 'JavaScript';
rest[0] === 'Elm';

31. const head = ([x]) => x;

32. const head = ([x]) => x;

33. const head = ([x]) => x;

34. const greet = (name, greeting = 'Hi') => {
console.log(greeting, name);
};
greet('DevNexus', 'Hello');
// Hello DevNexus
greet('Atlanta');
// Hi Atlanta

35. const greet = (name, greeting = 'Hi') => {
console.log(greeting, name);
};
greet('DevNexus', 'Hello');
// Hello DevNexus
greet('Atlanta');
// Hi Atlanta

36. const greet = (name, greeting = 'Hi') => {
console.log(greeting, name);
};
greet('DevNexus', 'Hello');
// Hello DevNexus
greet('Atlanta');
// Hi Atlanta

37. const greet = (name, greeting = 'Hi') => {
console.log(greeting, name);
};
greet('DevNexus', 'Hello');
// Hello DevNexus
greet('Atlanta');
// Hi Atlanta

38. Object.assign(
{},
{ hello: 'Atlanta' },
{ hi: 'DevNexus' }
);
// {
// hello: 'Atlanta',
// hi: 'DevNexus'
// }

39. Object.assign(
{},
{ hello: 'Atlanta' },
{ hi: 'DevNexus' }
);
// {
// hello: 'Atlanta',
// hi: 'DevNexus'
// }

40. Object.assign(
{},
{ hello: 'Atlanta' },
{ hi: 'DevNexus' }
);
// {
// hello: 'Atlanta',
// hi: 'DevNexus'
// }

41. class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
moveBy(dx, dy) {
this.x += dx;
this.y += dy;
}
}
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.moveBy =
function(dx, dy) {
this.x += dx;
this.y += dy;
};

42. PURE

43. const add = (x, y) => x + y;

44. const add = (x, y) => x + y;
Referentially
transparent

45. × let name = 'Jeremy';
const getName = () => name;
const setName = (newName) => {
name = newName;
};
const printUpperName = () => {
console.log(name.toUpperCase());
};

46. × let name = 'Jeremy';
const getName = () => name;
const setName = (newName) => {
name = newName;
};
const printUpperName = () => {
console.log(name.toUpperCase());
};

47. × let name = 'Jeremy';
const getName = () => name;
const setName = (newName) => {
name = newName;
};
const printUpperName = () => {
console.log(name.toUpperCase());
};

48. × let name = 'Jeremy';
const getName = () => name;
const setName = (newName) => {
name = newName;
};
const printUpperName = () => {
console.log(name.toUpperCase());
};

49. describe('api', () => {
beforeEach(() => mockConsoleLog());
afterEach(() => restoreConsoleLog());
it('sets and prints the name', () => {
printUpperName();
expect(console.log).calledWith('JEREMY');
setName('Jet');
printUpperName();
expect(console.log).calledWith('JET');
});
});
×

50. HIDDEN STATE IS
UNCERTAIN STATE

51. const upperName = (name) => name.toUpperCase();
describe('api', () => {
it('returns an uppercase name', () => {
expect(upperName('Jeremy')).to.equal('JEREMY');
expect(upperName('Jet')).to.equal('JET');
});
});

52. HOW TO ACHIEVE THE
RESULT
IMPERATIVE

53. function doubleNumbers(numbers) {
const doubled = [];
const l = numbers.length;
for (let i = 0; i < l; i++) {
doubled.push(numbers[i] * 2);
}
return doubled;
}
doubleNumbers([1, 2, 3]);
// [2, 4, 6]

54. DECLARE WHAT THE
DESIRED RESULT IS
DECLARATIVE

55. function doubleNumbers(numbers) {
return numbers.map(n => n * 2);
}
doubleNumbers([1, 2, 3]);
// [2, 4, 6]

56. function doubleNumbers(numbers) {
return numbers.map(n => n * 2);
}
doubleNumbers([1, 2, 3]);
// [2, 4, 6]

57. 1
2
3
numbers.map(n => n * 2)
2
4
6
Domain Range

58. CREATE STATE, DON’T
MUTATE IT
IMMUTABLE

59. const hobbies = [
'programming',
'music',
];
const firstTwo = hobbies.splice(0, 2);
console.log(firstTwo);
console.log(hobbies);
// ['music']

60. const hobbies = [
'programming',
'music',
];
const firstTwo = hobbies.splice(0, 2);
console.log(firstTwo);
console.log(hobbies);
// ['music']
Slight typo + mutability

61. Object.freeze
Immutable.js

62. const hobbies = Object.freeze([
'programming',
'music',
]);
const firstTwo = hobbies.splice(0, 2);
// TypeError

63. const hobbies = Object.freeze([
'programming',
'music',
]);
const firstTwo = hobbies.splice(0, 2);
// TypeError

64. FREE YOUR
STATE

65. class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
moveBy(dx, dy) {
this.x += dx;
this.y += dy;
}
}
const point = new Point(0, 0);
point.moveBy(5, 5);
point.moveBy(-2, 2);
console.log([point.x, point.y]);
// [3, 7]
×

66. const createPoint = (x, y) => Object.freeze([x, y]);
const movePointBy = ([x, y], dx, dy) => {
return Object.freeze([x + dx, y + dy]);
};
let point = createPoint(0, 0);
point = movePointBy(point, 5, 5);
point = movePointBy(point, -2, 2);
console.log(point);
// [3, 7]

(*or object-oriented
without mutation)

67. const createPoint = (x, y) => Object.freeze([x, y]);
const movePointBy = ([x, y], dx, dy) => {
return Object.freeze([x + dx, y + dy]);
};
let point = createPoint(0, 0);
point = movePointBy(point, 5, 5);
point = movePointBy(point, -2, 2);
console.log(point);
// [3, 7]

(*or object-oriented
without mutation)

68. const createPoint = (x, y) => Object.freeze([x, y]);
const movePointBy = ([x, y], dx, dy) => {
return Object.freeze([x + dx, y + dy]);
};
let point = createPoint(0, 0);
point = movePointBy(point, 5, 5);
point = movePointBy(point, -2, 2);
console.log(point);
// [3, 7]

(*or object-oriented
without mutation)

69. const createPoint = (x, y) => Object.freeze([x, y]);
const movePointBy = ([x, y], dx, dy) => {
return Object.freeze([x + dx, y + dy]);
};
let point = createPoint(0, 0);
point = movePointBy(point, 5, 5);
point = movePointBy(point, -2, 2);
console.log(point);
// [3, 7]

(*or object-oriented
without mutation)

70. PROS
SAFETY FROM ACCIDENTAL MUTATION
FREE UNDO/REDO LOGS — REDUX
EXPLICIT FLOW OF DATA
CONCURRENCY SAFETY

71. CONS
VERBOSE
MORE OBJECT CREATION*
MORE GARBAGE COLLECTION*
MORE MEMORY USAGE*
*Alleviated with libs like Immutable.js

72. FIRST CLASS
FUNCTIONS

73. const multiply = (x, y) => x * y;
return x + y;
}
const evens = [1, 2, 3].map(n => n * 2);

74. const multiply = (x, y) => x * y;
return x + y;
}
const evens = [1, 2, 3].map(n => n * 2);

75. const multiply = (x, y) => x * y;
return x + y;
}
const evens = [1, 2, 3].map(n => n * 2);

76. const multiply = (x, y) => x * y;
return x + y;
}
const evens = [1, 2, 3].map(n => n * 2);

77. ENCAPSULATION
CLOSURES

78. const createAdder = (x) => {
return (y) => x + y;
};

79. const createAdder = (x) => {
return (y) => x + y;
};

80. const request = (options) => {
return fetch(options.url, options)
.then(resp => resp.json());
};
const usersPromise = request({
url: '/users',
});
});

81. const request = (options) => {
return fetch(options.url, options)
.then(resp => resp.json());
};
const usersPromise = request({
url: '/users',
});
});
Repetitive

82. const createRequester = (options) => {
return (otherOptions) => {
return request(Object.assign(
{}, options, otherOptions
));
};
};
const customRequest = createRequester({
});
const usersPromise = customRequest({ url: '/users' });

83. const createRequester = (options) => {
return (otherOptions) => {
return request(Object.assign(
{}, options, otherOptions
));
};
};
const customRequest = createRequester({
});
const usersPromise = customRequest({ url: '/users' });

84. FOUNDATION FOR
HIGHER ORDER
PATTERNS
FIRST CLASS
CLOSURES

85. PARTIAL
APPLICATION

86. const createAdder = (x) => {
return (y) => x + y;
};
const createRequester = (options) => {
return (otherOptions) => {
return request(Object.assign(
{}, options, otherOptions
));
};
};
RECALL

87. const add = (x, y) => x + y;

88. const add = (x, y) => x + y;

89. const request = (defaults, options) => {
options = Object.assign({}, defaults, options);
return fetch(options.url, options)
.then(resp => resp.json());
};
const customRequest = partial(request, {
});
const usersPromise = customRequest({ url: '/users' });

90. const request = (defaults, options) => {
options = Object.assign({}, defaults, options);
return fetch(options.url, options)
.then(resp => resp.json());
};
const customRequest = partial(request, {
});
const usersPromise = customRequest({ url: '/users' });

91. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

92. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

93. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

94. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

95. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

96. const partialFromBind = (fn, ...args) => {
return fn.bind(null, ...args);
};
const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(...args, ...otherArgs)
};
};

97. CURRYING

const customRequest = request({
});
const usersPromise = customRequest({ url: '/users' });

const customRequest = request({
});
const usersPromise = customRequest({ url: '/users' });

100. const add = x => y => x + y;
return function(y) {
return x + y;
};
}

101. const add = x => y => x + y;
return function(y) {
return x + y;
};
}

102. const add = x => y => x + y;
return function(y) {
return x + y;
};
}

103. const request = defaults => options => {
options = Object.assign(
{}, defaults, options
);
return fetch(options.url, options)
.then(resp => resp.json());
};

104. const request = defaults => options => {
options = Object.assign(
{}, defaults, options
);
return fetch(options.url, options)
.then(resp => resp.json());
};

105. PIECING IT
TOGETHER

106. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

107. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

108. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

109. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

110. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

111. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

112. const map = fn => array => array.map(fn);
const multiply = x => y => x * y;
const pluck = key => object => object[key];
const discount = multiply(0.98);
const tax = multiply(1.0925);
const customRequest = request({
});
customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));

113. customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));
[
{ price: 5 },
{ price: 10 },
{ price: 3 },
]

114. [
{ price: 5 },
{ price: 10 },
{ price: 3 },
]
map(pluck('price'))
[
5,
10,
3,
]
item.price

115. [
5,
10,
3,
]
map(discount)
[
4.9,
9.8,
2.94,
]
price * 0.98

116. [
5.35,
10.71,
3.21,
]
map(tax)
[
4.9,
9.8,
2.94,
]
price * 1.0925

117. COMPOSING
CLOSURES

118. const processWord =
compose(hyphenate, reverse, toUpperCase);
const words = [
'hello', 'functional', 'programming'
];
const newWords = words.map(processWord);
console.log(newWords);
// ['OL-LEH, 'LANOI-TCNUF', 'GNIMM-ARGORP']

119. const processWord =
compose(hyphenate, reverse, toUpperCase);
const words = [
'hello', 'functional', 'programming'
];
const newWords = words.map(processWord);
console.log(newWords);
// ['OL-LEH, 'LANOI-TCNUF', 'GNIMM-ARGORP']

120. const processWord =
compose(hyphenate, reverse, toUpperCase);
const processWordExplicit = (word) => {
return hyphenate(reverse(toUpperCase(word)));
};

121. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

122. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

123. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

124. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

125. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

126. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);

127. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);
fns = [hyphenate, reverse, toUpperCase]
arg = result = 'hello'

128. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);
fns = [hyphenate, reverse]
result = 'HELLO'

129. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);
fns = [hyphenate]
result = 'OLLEH'

130. const compose = (...fns) => arg => (
fns.reduceRight(
(result, fn) => fn(result),
arg
)
);
fns = []
result = 'OL-LEH'

131. customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax));
RETURNING TO PRICES EXAMPLE

132. customRequest({ url: '/cart/items' })
.then(map(pluck('price')))
.then(map(discount))
.then(map(tax)); Triple
iteration
RETURNING TO PRICES EXAMPLE

133. customRequest({ url: '/cart/items' })
.then(map(
compose(
tax,
discount,
pluck('price')
)
));
Single
iteration

134. RECURSION SOLVE A PROBLEM
IN TERMS OF ITSELF

135. FACTORIAL

136. const factorial = (n) => {
let result = 1;
while (n > 1) {
result *= n;
n--;
}
return result;
};

137. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};

138. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
Recursive call

139. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
Base case

140. factorial(4);

141. factorial(4);
4 * factorial(3);

142. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);

143. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);

144. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;

145. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;

146. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;

147. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

148. STEPS
Find the recurrence
(n × n-1 × n-2 × … 1)
Find the base case
(n < 2)

149. PERFORMANCE
RECURSION

150. const value = factorial(100000);
console.log(value); // ???
WHAT IS THE RESULT?

151. const value = factorial(100000);
console.log(value); // ???
WHAT IS THE RESULT?
RangeError: Maximum call
stack size exceeded

152. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

Call Stack

153. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
Call Stack

154. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
factorial(3)
Call Stack

155. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
factorial(3)
factorial(2)
Call Stack

156. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
factorial(3)
factorial(2)
factorial(1)
Call Stack

157. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
factorial(3)
factorial(2)
Call Stack

158. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
factorial(3)
Call Stack

159. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

factorial(4)
Call Stack

160. factorial(4);
4 * factorial(3);
4 * 3 * factorial(2);
4 * 3 * 2 * factorial(1);
4 * 3 * 2 * 1;
4 * 3 * 2;
4 * 6;
24;

Call Stack

161. const value = factorial(100000);
console.log(value); // ???
100,000 calls = 100,000 stack frames
1 stack frame ≈ 48B
Max stack usage ≈ 1MB
100,000 x 48 / 1024 / 1024 = 4.58MB > 1MB

162. IN ES2015!
TAIL CALL
OPTIMIZATION

163. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
UNOPTIMIZABLE

164. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
1
UNOPTIMIZABLE

165. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
1
UNOPTIMIZABLE
2

166. const factorial = (n) => {
if (n < 2) {
return 1;
}
return n * factorial(n - 1);
};
1
UNOPTIMIZABLE
2
3

167. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
OPTIMIZABLE

168. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
OPTIMIZABLE

169. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
OPTIMIZABLE

170. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
OPTIMIZABLE

171. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
1
OPTIMIZABLE

172. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
1
2
OPTIMIZABLE

173. const factorial = (n, accum = 1) => {
if (n < 2) {
return accum;
}
return factorial(n - 1, n * accum);
};
1
2
3
OPTIMIZABLE

174. const value = factorial(100000);
console.log(value);
// Infinity

175. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

Call Stack

176. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

factorial(4, 1)
Call Stack

177. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

factorial(3, 4)
Call Stack

178. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

factorial(2, 12)
Call Stack

179. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

factorial(1, 24)
Call Stack

180. factorial(4 /*, 1 */);
factorial(3, 4);
factorial(2, 12);
factorial(1, 24);
24;

Call Stack

181. RECAP
PREDICTABLE
SAFE
TRANSPARENT
MODULAR

182. DEMO

183. RESOURCES

Brian Lonsdorf

185. ES6/7/LATER
babeljs.io

186. LANGUAGES
Elm (elm-lang.org)
Clojurescript (github.com/clojure/clojurescript)
Purescript (purescript.org)

187. LIBRARIES
Lodash (lodash.com)
Ramda (ramdajs.com)
Rx (reactivex.io)
Bacon.js (baconjs.github.io)