First: The basics
Variable declaration
// ES5
var foo;
var bar;
// ES6
let foo;
const bar = 'bar';
What happens to let?
Scope
for (var i = 0; i < cars.length; i++) {
// i is visible here
}
// i is visible here
for (let x = 0; x < cars.length; x++) {
// x is visible here
}
// x is not visible here
var is scoped to the nearest function block and let is only defined in the current block of code
Scope
function() {
for (var i = 0; i < cars.length; i++) {
// i is visible here
}
// i is visible here
}
// i is not visible here
there are 2 types of scope. Local and global
Each function creates a new scope and it determines the visibility of these variables
Assignation
Variable assignation
// ES5
var foo = 4;
var bar = 'bar';
// ES6
const foo = 4;
const bar = 'bar';
let salvame;
salvame = null;
let telecinco = null;
telecinco = 0;
Where do i declare my variables?
Hoisting
It's always better to declare your variables at the top because JavaScript moves variable declarations at the top in a process called hoisting
Comparing values...
Comparission
const x = 5;
x === 5; // Strict type and value
x == '5'; // Compare only value
// Not equal
x != '5';
x !== '5';
// Greater than
x > 3;
x >= 5;
Operators
NaN... NaN
Operators...
const x = 5;
x = 5 - 3 // 2
x = 5 * 2 // 10
x += 2 // 12
x *= 2 // 24
x /= 2 // 12
x %= 2 // 0
x++ // Increments 1
x-- // Decrements 1
x ** y // Exponentiation
Operators...
const x = 5;
const y = -x // y === -5
const z = +y // z === 5
// Logical operators
// && and
(5 < 10 && 10 > 1)
// || or
(5 > 10 || 10 > 1)
// ! not
!false // true
// Ternary operator
const a = x > 10 ? 'car' : 'house';
WAT
Comparission Common pitfails
// Common comparission pitfails
// Arrays instances are stored in differents parts of the memory
console.log([] == [])
// Objects too are different
console.log({} == {})
// Variables can point to the same reference of memory
var a,b;
a = b = {};
console.log(a == b);
// Double equal comparision will make javascript convert values to it's integer value
// And the number value of [] is 0 -> Number([])
// false, null, undefined, NaN, 0, '' and "" are considered falsy, and the number value of false is 0
console.log([] == false)
// Null with relational operators is casted to its Number value, 0
console.log(0 < null)
// This does not happen with the == operator
console.log(0 == null)
Comparission Common pitfails
// Is true
console.log([10] == 10)
// Is false
console.log([10] === 10)
// Is true
console.log('10' == 10)
// Is false
console.log('10' === 10)
// Is true
console.log([] == 0)
// Is false
console.log([] === 0)
// Is true
console.log('' == false)
// Is false
console.log('' === false)
Operators Common Pitfails
// Number + Number -> addition
console.log(1 + 2);
// Boolean + Number -> addition
console.log(true + 1)
// Boolean + Boolean -> addition
console.log(false + false);
// Number + String -> concatenation
console.log(5 + 'foo')
// String + Boolean -> concatenation
console.log('foo' + false)
// String + String -> concatenation
console.log('foo' + 'bar')
JavaS... TRICKS
// !! is used to produce a true/false based on truthy/falsy values
!!something
// Using OR to select the truthy value
const a = b || c
// Using AND as a safe accessor
if( a && a.method ) {
}
// Conver to a number
let one = '1'
let numberOne = +one
fn()
Function declaration
// ES5
function suma (a, b) {
return a + b
}
// ES6
const resta = (a, b) => a - b
=>
JavaScript supports different styles of programming
Modern tendencies are influenced by the functional approach
JavaScript can be functional
High order functions. The ability to pass functions as arguments, assign them to variables, return functions...
JavaScript can be functional
function doSomething() {
return function() {
// HI!
}
}
return functions
JavaScript can be functional
function doSomething(cb) {
return function() {
console.log('hey');
cb();
}
}
pass functions as arguments
JavaScript can be functional
function unless(test, then) {
if (!test) then();
}
unless(x, function() {
// Only if x is falsy
})
even create new structures of control
JavaScript can be functional
Anonymous functions and lambda syntax () => x
x => x * 2
const multiplyItemsBy2 = (a) => a.map(x => x * 2)
JavaScript can be functional
Closures. A function defined inside a function gets access to its variable binding
function creaSumador(x) {
var movida = 'sumando';
return function(y) {
console.log(movida);
return x + y;
};
}
var suma5 = creaSumador(5);
JavaScript can be functional
JavaScript has the Array helpers, map, filter, find, reduce
JavaScript can be functional
Pure functions.
Functions that always return the same result given certain parameters. They never mutate the data.
JavaScript can be functional
Inmutability. For ensuring functional programming and avoiding side effects.
For example, we can create new objects with:
Object.assign({}, myObj, newProperties);
{
...myObj,
...newProperties
}
JavaScript can be functional
What is not a pure function?
var x = {
prop: 'pepito'
}
function stuff(obj) {
obj.casa = 'negra'
return obj
}
/* Not good */
stuff(x)
JavaScript can be functional
What is a pure function?
var x = {
prop: 'pepito'
}
function stuff(obj) {
return Object.assign({}, obj, { casa: 'negra' })
}
/* Much better */
stuff(x)
JavaScript can be functional
Function composition
Function composition is the process of combining two or more functions to produce a new function.
A maths example: f(g(x))
Reads as x then g then f
JavaScript can be functional
Function composition
function add(a, b) {
return a + b
}
function multiply(a, b) {
return a * b
}
const result = add(multiply(3, 2), 5)
JavaScript can be functional
Partial application
Giving a function with M arguments. Is the process of applying a function with N arguments and return a function with X arguments
Where: M > N
and : M > X
JavaScript can be functional
Partial application
function add(a, b) {
return a + b
}
function multiply(a, b) {
return a * b
}
const multiplyAndAdd = (a, b) => {
return (c) => add(multiply(a,b), c)
}
multiplyAndAdd(3,2)(5)
JavaScript can be functional
Currying
Is the process of receiving a function with multiple parameters and returning a function with exactly ONE parameter
JavaScript can be functional
Currying
function toloco(one, two, three, four) {
// Do something
}
const toCurry = curry(toloco)
const toCurryA = toCurry(a)
const toCurryB = toCurry(b)
toCurryA(b)
What is functional?
function composition
currying / partial application
inmutability
pure functions
Values we want to achieve
Having small & concise pieces of code that have no side effect, that can be both testable and composable. Super fancy shit yeah.
...this is not a religion
You can combine OOP with functional programming
JavaScript functional - Level 1
const suma = (a, b) => a + b
const sumaCurrificada = (a) => (b) => a + b
// Or partially applied
suma3 = sumaCurrificada(3)
suma3(2) // 5
// Using ramda
const sum10 = R.curry(suma)(10)
sum10(30) // 40
sum10(90) // 120
Currying
JavaScript functional - Level 1
Create a function that:
- Receives a user object and a property name (string)
- Returns a new user object with that property setted to "test"
- Make the function curryfied or partial applied so you can pass different property parameters
JavaScript functional - Level 1
Spread operator
Let's you create a new object.
const user = {
name: 'test',
surname: 'pepito',
email: '123@gmail.com'
}
const newUser = {
...user,
email: '234@gmail.com
}
JavaScript functional - Level 1b
Change your previous function to use the new spread operator
Spread operator
It allows you to extract properties from an object (destructuring assignment)
const request = {
headers: {},
body: {
name: 'test'
},
queryParams: {
camaign: 'test'
}
}
const { headers, ...noHeadersRequest } = request
JavaScript functional - Level 2
Create a function that:
- Receives 2 parameters, one is the user and the other is the new user data (object)
- Returns a new user object with the properties updated but remove at least 2 properties from the original user
JavaScript functional - Level 2
const user = {
name: 'abc',
email: 'test@test.com',
address: {
street: '1'
},
metadata: ['a', 'b', 'c']
}
myFunc(user, { email: 'email@email.com' })
/*
{
name: 'abc',
email: 'email@email.com'
}
*/
Spread operator
It allows you to concat arrays
const a = [1, 2, 3, 4]
const b = [0, ...a, 5, 6, 7, 8]
Spread operator
It allows you to extract properties from an array (destructuring assignment)
const colors = ['green', 'red', 'yellow', 'pink']
const [first, second, ...rest] = colors
Inmutable array iteration
Without map...
const users = [{
name: 'Pedro',
age: 15
}, {
name: 'Javier',
age: 30
}, {
name: 'Maria',
age: 25
}]
const userAges = []
for(var i = 0; i < users.length; i++) {
userAges.push(users[i].age)
}
// [15, 30, 25]
Map
Array has different methods, one of them is .map() which is really useful in functional programming. It returns a new array with the returned result of the callback function
const users = [{
name: 'Pedro',
age: 15
}, {
name: 'Javier',
age: 30
}, {
name: 'Maria',
age: 25
}]
const userAges = users.map(u => u.age)
// [15, 30, 25]
Map
Array methods are also chainable...
const takeAge = (u) => u.age
const squareIt = (n) => n * n
users.map(takeAge)
.map(squareIt)
[].reduce
const ages = users.reduce(function(acc, next) {
return acc + next.age
}, 0)
Function Composition
Function composition is the ability to pass the result of one function to another.
const sum10 = (a) => a + 10
const multiplyBy5 = (b) => b * 5
console.log(sum10(multiplyBy5(10)))
const sumAndMultiply = R.compose(sum10, multiplyBy5)
console.log(sumAndMultiply(10))
Putting this together...
const users = [{
born: 1985,
died: 2017,
sex: 'm'
},{
born: 1955,
died: 2017,
sex: 'm'
},{
born: 1935,
died: 2017,
sex: 'm'
},{
born: 1995,
died: 2008,
sex: 'f'
}{
born: 1985,
died: 2017,
sex: 'f'
},{
born: 1955,
died: 2001,
sex: 'f'
}]
Putting this together...
function average(array) {
function plus(a, b) { return a + b; }
return array.reduce(plus) / array.length;
}
function age(p) { return p.died - p.born; }
function male(p) { return p.sex == "m"; }
function female(p) { return p.sex == "f"; }
console.log(average(ancestry.filter(male).map(age)));
// → 61.67
console.log(average(ancestry.filter(female).map(age)));
// → 54.56
JavaScript functional - Level 3 - Time 15 min
Create a script that combines the following techniques:
- Function composition
- Array map
- Spread operator
JavaScript functional - Level 3 - Time 15 min
const numbers = [2, 3, 4, 5, 6]
const result = myFunc(numbers)
/*
{
first: 40,
second: 60,
rest: [40, 50, 60]
}
*/
A quick tip
We are going to learn about Function.prototype.apply && Function.prototype.call
Every JavaScript object has a prototype. The prototype is also an object.
All JavaScript objects inherit their properties and methods from their prototype.
A quick tip
We can call a function in 4 different ways.
myFunction(a);
obj['myFunction'](a);
myFunction.call(null, a)
myFunction.apply(null, [a])
JavaScript functional - Level 4 - Time 15 min
Create a function "partialApply" that:
- Receives a function and N arguments and partially applies those arguments to the function
- Test your `partialApply` function with another function that receives N arguments
Install nodejs
Testing
What is Unit testing?
Unit testing is the process of writing tests for small units of code. This process ensures that the code works correctly and accomplishes it's purpose.
It should be isolated from the dependencies
Testing
BDD?
BDD is a set of best practices for writing great tests. BDD can, and should be, used together with TDD and unit testing methods.
It enforces focusing on what the code should do rather than in the implementation details
Testing
What is mocha?
Mocha is a test framework that runs in NodeJs and in the browser.
Testing
It allows us to define the test suites as the following
describe('My test suite', () => {
describe('one thing', () => {
it('should go well', () => {
assert.ok(true);
})
})
})
Testing
It has the following hooks
describe('hooks', function() {
before(function() {
// runs before all tests in this block
});
after(function() {
// runs after all tests in this block
});
beforeEach(function() {
// runs before each test in this block
});
afterEach(function() {
// runs after each test in this block
});
// test cases
});
Testing
ChaiJS
Is a BDD / TDD assertion library
I always prefer the BDD assertion style
expect(function () {}).to.not.throw();
expect({a: 1}).to.not.have.property('b');
expect([1, 2]).to.be.an('array').that.does.not.include(3);
Testing
Clone repo
https://github.com/rafinskipg/test-functional-boilerplate
Launch tests
npm test
Make tests go green.
You can submit a pull request with your implementation for further feedback
JavaScript functional
Write a maybe function
Write tests for your maybe function
JavaScript functional
Write a "once" function
Write tests for the once function
Final monster
Merge branch
git pull origin final-countdown
Discover new requirements
npm test
Make tests go green.
You can submit a pull request with your implementation for further feedback
Links
Ramda JS
ramdajs.com/docs/
Lodash