JavaScript
Slack
JavaScript Syntax
First: The basics
Variable declaration
// ES5
var foo;
var bar;
// ES6
let foo;
const bar = 'bar';
Variable declaration
// ES5
var foo = 5;
var bar = true;
var zet = 'zet';
var list = [];
var obj = {};
Variable declaration
var foo = [1, 2, 3];
var foo = {
property: false,
otherProperty: 15
}
Variable declaration
var foo = [{
name: 'test',
email: 'test@email.com'
}, {
name: 'test2',
email: 'test@email.com'
}]
Variable declaration
var foo = {
name: 'test',
email: 'test@email.com',
list: [1, 3, 4, 5],
otherProperty: {
hello: stuff
}
}
Variable assignation
var salvame;
salvame = null;
var telecinco = null;
telecinco = 0;
Variable assignation
var salvame;
function doNotWatchTv() {
salvame = null;
}
doNotWatchTv();
Variable assignation
var salvame;
telecinco = 0;
function doNotWatchTv() {
salvame = null;
}
var telecinco;
doNotWatchTv();
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
Operators
Operators
Unary operators
A unary operator is one that takes a single operand/argument and performs an operation.
OperatorExplanation
Unary plus (+) | Tries to convert the operand into a number |
Unary negation (-) | Tries to convert the operand into a number and negates after |
Logical Not (!) | Converts to boolean value then negates it |
Increment (++) | Adds one to its operand |
Decrement (--) | Decrements by one from its operand |
Bitwise not (~) | Inverts all the bits in the operand and returns a number |
typeof | Returns a string which is the type of the operand |
delete | Deletes specific index of an array or specific property of an object |
void | Discards a return value of an expression. |
+ operator
Tries to convert the operand to a number
+3 // returns 3
+'-3' // returns -3
+'3.14' // returns 3.14
+'3' // returns 3
+'0xFF' // returns 255
+true // returns 1
+'123e-5' // returns 0.00123
+false // returns 0
+null // returns 0
+'Infinity' // returns Infinity
+'infinity' // returns NaN
+function(val){ return val } // returns NaN
+ operator
If a object has a valueOf method, that value will be returned
+{
valueOf: function(){
return '0xFF'
}
}
//255
- operator
Tries to convert the operand to a number, but performs a negation
-3 // returns -3
-'-3' // returns 3
-'3.14' // returns -3.14
-'3' // returns -3
-'0xFF' // returns -255
-true // returns -1
-'123e-5' // returns -0.00123
-false // returns -0
-null // returns -0
-'Infinity' // returns -Infinity
-'infinity' // returns NaN
-function(val){ return val } // returns NaN
-{
valueOf: function(){
return '0xFF'
}
} //returns -255
! operator
Converts the value to it's boolean representantion before negating
!false // returns true
!NaN // returns true
!0 // returns true
!null // returns true
!undefined // returns true
!"" // returns true
!true // returns false
!-3 // returns false
!"-3" // returns false
!42 // returns false
!"42" // returns false
!"foo" // returns false
!"true" // returns false
!"false" // returns false
!{} // returns false
![] // returns false
!function(){} // returns false
!! operator
Converts the value to it's boolean representation
!!false // returns false
!!true // returns true
!!1 // returns true
!!0 // returns false
++ operator
Increments by one it's value
Can be used in 2 ways.
Before:
var x = 5;
var y = ++x;
// x === 6
// y === 6
var x = 5;
var y = x++;
// x === 6
// y === 5
After
It returns the value before modifying
-- operator
Decrements by one it's value
Can be used in 2 ways.
Before:
var x = 5;
var y = --x;
// x === 4
// y === 4
After
It returns the value before modifying
var x = 5;
var y = x--;
// x === 4
// y === 5
typeof operator
returns a string indicating the type of the value
typeof 2 // returns 'number'
typeof true // returns 'boolean'
typeof null // returns 'object'
typeof Infinity // returns 'number'
typeof '2' // returns 'string'
typeof '-3' // returns 'string'
typeof 'infinity' // returns 'string'
typeof Date() // returns 'string'
typeof [1,2,3] // returns 'object'
typeof {hi: 'world'} // returns 'object'
typeof function(val){ return val } // returns 'function'
typeof undefined // returns 'undefined'
typeof hi // returns 'undefined'
typeof NaN // returns 'number'
typeof new Date() // returns 'object'
delete operator
deletes a object propery and returns true if it was succesful
// Deleting a property with the dot notation
var pub = { bar: "42" };
delete pub.bar; // returns true
console.log(pub); // returns {}
// Deleting a property that does not exist
var lunch = { fries: 1 };
delete lunch.beans; // returns true
console.log(lunch); // returns { fries: 1 }
// Deleting a non-configurable property of a predefined object
delete Math.PI; // returns false
console.log(Math.PI); // returns 3.141592653589793
delete operator
deletes a object propery and returns true if it was succesful
// Deleting a property with the dot notation
var pub = { bar: "42" };
delete pub.bar; // returns true
console.log(pub); // returns {}
// Deleting a property that does not exist
var lunch = { fries: 1 };
delete lunch.beans; // returns true
console.log(lunch); // returns { fries: 1 }
// Deleting a non-configurable property of a predefined object
delete Math.PI; // returns false
console.log(Math.PI); // returns 3.141592653589793
non configurable properties
delete has no effect on non configurable properties
var Person = {};
Object.defineProperty(Person, 'name',
{
value: 'Scot',
configurable: false
})
// Defines an object property and sets it to non-configurable
console.log(Person.value); // returns 'Scot'
delete Person.value // returns false
console.log(Person.value); // returns 'Scot'
== Comparission / unestrict equality
1 == 1 // true
"1" == 1 // true
1 == '1' // true
0 == false // true
0 == null // false
0 == undefined // false
null == undefined // true
Tries to convert it's type
== Comparission
[] == [] // false
{} == {} // false
// Not same reference of memory
Comparission Common pitfails
// Is true
console.log([10] == 10)
// Is true
console.log('10' == 10)
// Is true
console.log([] == 0)
// Is true
console.log('' == false)
=== Comparission / strict equality
1 === 1 // true
1 === '1' // false
false === 0 // false
Enforces strict type equality
!= unestrict inequality / !== strict inequality
1 != 2 // true
1 != '1' // false
1 != "1" // false
1 != true // false
0 != false // false
1 !== 2 // true
1 !== '1' // true
1 !== "1" // true
1 !== true // true
0 !== false // true
>, <, >=, <= relational operators
0 >= null // true
0 < null // false
1 < '3' // true
'z' > 'a' // true
JavaScript coerces into its primitive number type
Logical operators
Logical operators are used to determine the logic between variables or values.
&&
||
!
Logical operators
Logical operators are used to determine the logic between variables or values.
(x < 10 && y > 1) // true
1 && "false" // true
1 || false // true
0 || "true" // true
truthy falsey
Truthy: Something which evaluates to TRUE.
Falsey: Something which evaluates to FALSE.
undefined, null, NaN, 0, "" (empty string), and false
logical operator assignation
&& gives you the last value
|| gives you first value
3 && 7 // 7
3 || 7 // 3
false || 7 // 7
Arithmetic Operators
// Sum tries to perform string or number additions
var a = 5
a = a + 5
// Same as
a += 5
// Multiply only has number coercion
var a = 5;
a = a * 10
// Same as
a *= 10
Arithmetic Operators
// Division operator
var a = 5
a = a / 5
// Same as
a /= 5
// Remaining operator
var a = 6;
a = a % 5
// Same as
a %= 5
Arithmetic Operators
// exponentation operator
var a = 5
a = a ** 3
// 125
Arithmetic 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')
Arithmetic Operators Common Pitfails
// String - Number -> NaN
console.log('foo' - 3)
// The addition operator performs string or number operators.
// JavaScript will translate [] into it's string equivalent ''
console.log([] + [])
// empty string
// [].toString() + [].toString()
// The operator - is not defined for strings
// then JavaScript will transform the value to number
console.log([] - [])
// Number([]) - Number([])
// NaN
WAT
Ternary operator
var result = condition ? result1 : result2
var result = 0 == false ? 15 : 20
var otherResult = [] == [] ? 15 : 20
.... Spread operator
spread syntax
The spread operator allows an array to be expanded where N arguments for function calls or array elements are expected
.... Spread operator
spread syntax
var list = ['a', 'b', 'c']
function log(x, y, z) {
console.log(x, y, z)
}
log(...list)
.... Spread operator
spread syntax
var list = ['a', 'b', 'c']
function log(x, ...rest) {
console.log(x, rest)
}
log(...list)
.... Spread operator
spread syntax
var list = ['a', 'b', 'c']
var newList = ['d', 'e', ...list, 'z' ]
Spread operator exercise
- merge two arrays [1, 2, 3] [4, 5, 6]
- Define a function that receives several arguments, call that function with the array values spreaded
.... Spread operator
spread syntax
The spread operator allows an object to be expanded inplaces where N object key-value pairs are expected
.... Spread operator
spread syntax
var obj = {
field: 'value',
anotherField: 'value2'
}
var newObj = {
...obj,
thirdField: 'value3'
}
Spread operator exercise
Merge two objects.
.... Spread operator
destructuring assignment
const allNumbers = [1, 2, 3, 4]
const [first, second, ...rest] = allNumbers
// first 1
// second 2
// rest [3, 4]
.... Spread operator
destructuring assignment
const user = {
name : 'myname',
address: {
city: 'madrid'
},
pwd: '134'
}
const { name, ...restObjData } = user
Destructuring assignment exercise
Given an array [1,2,3,4,5,6], get the last 3 items in a new array copy.
Scope & Closures
Scope
scope determines the visibility of variables and other resources in areas of your code.
There are 3 types of scope: Global, local and block
Scope
A new function creates a new scope. That scope is local to that function.
var x = 0; // Global scope
function doMaths() {
var y = 0;
}
console.log(x);
// console.log(y)?
Scope
the control structures create a new block scope
var x = 0; // Global scope
function doMaths() {
for(let i = 0; i < 10; i++) {
// Block scope
}
// console.log(i)?
}
console.log(x);
// console.log(y)?
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
We can access the parent scope
var x = 1; // Global scope
function doMaths() {
var b = 3;
function sum() {
return x + b;
}
return sum();
}
Scope
We can access the parent scope
var x = 1; // Global scope
function doMaths() {
var x = 3;
x = 5 + x;
return x
}
Closures
A Closure is created when an inner function tries to access the scope chain of its outer function
function makeSumator(a) {
var x = 3;
return function(b) {
return b + x + a
}
}
const sumatorThree = makeSumator(3)
const sumatorSeven = makeSumator(7)
sumatorThree(5) // 5 + 3 + 3
sumatorThree(6) // 6 + 3 + 3
sumatorSeven (5) // 5 + 3 + 7
sumatorSeven (6) // 6 + 3 + 7
Closures
makeSumator is a function factory that creates functions.
sumatorThree and sumatorSeven are both closures, they share the same body definition but have different lexical environment
Closures exercise
Create a function that:
- has a internal counter
- whenever i call the function the counter gets incremented.
- No one else can modify the counter (is not in the global scope)
Functions
=>
Functions
Functions are "subprograms" that can be executed
Functions
Functions have arguments and a body
function doSomething(arg1, arg2) {
// Do something fancy with arg1 or arg2
}
Functions
function arguments are passed by value, but if they are an object they get passed by reference
Functions
var x = {
thing : true
}
var name = 'name'
function doSomething(arg1, arg2) {
arg1.thing = false
arg2 += ' surname'
}
doSomething(x, name)
Functions
function myThing() {
return function() {
}
}
Functions can have a name or be anonymous
Functions
(function() {
// statements
})();
functions can be invoked only once
Functions
new Function (arg1, arg2, ... argN, functionBody)
functions can be created with the Function constructor
JavaScript supports different styles of programming
- Imperative
- Object Oriented
- Functional
Modern tendencies are influenced by the functional approach
- Inmutable data
- Pure functions
- Redux / RxJS ...
JavaScript can be functional
High order functions. The ability to pass functions as arguments, assign them to variables, return functions...
function doSomething() {
return function() {
// HI!
}
}
return functions
function doSomething(cb) {
return function() {
console.log('hey');
cb();
}
}
pass functions as arguments
function unless(test, then) {
if (!test) then();
}
unless(x, function() {
// Only if x is falsy
})
even create new structures of control
Anonymous functions and lambda syntax () => x
x => x * 2
const multiplyItemsBy2 = (a) => a.map(x => x * 2)
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)
To determine if a function is impure, if we call a function and expect no return value we can deduce that the function is not pure.
For functional programming returning no value means the function does nothing.
Inmutability. For ensuring functional programming and avoiding side effects.
For example, we can create new objects with:
Object.assign({}, myObj, newProperties);
{
...myObj,
...newProperties
}
JavaScript functional - Level 2
Create pure function that
- Receives a user object and a newData object
- Returns a new object with both of the data combined
TIP: Use spread operator or Object.assign
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
Utilities
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)
Function composition exercise
Combine 3 functions in the way f(g(c(x))) that will modify a number in different ways using arithmetic operators.
JavaScript functional
Given a user that has 2 number properties (age and money) combine 2 functions in the way:
f(g(x))
that return the a number equaling the age and money of the user multiplied between them, where x is the user.
JavaScript functional
function multiply(a, b) {
return a * b
}
function takeAgeAndMoney(u) {
return [u.age, u.money]
}
const u = {
age: 10,
money: 20
}
multiply(...(takeAgeAndMoney(u)))
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
Partial application
function add(a) {
return function(b) {
return a + b
}
}
const sumPartial = add(3)
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
Partial application
JavaScript functional - Partial Application
Create a function that:
- Do needs 4 parameters to be completed.
- Returns a function with half of its parameters
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)
JavaScript functional - Level 1
Create a function that receives 3 arguments and currify it.
Create different variations of the remaining function executions, each one will have it's own closure.
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)
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'
}]
JavaScript functional - Level 3 - Time 15 min
Create a script that combines the following techniques:
- Function composition
- Array map
- Array reduce
JavaScript functional - Level 4 - Time 15 min
Create a function that filters a subset of data.
Find one of the items by name.
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
To the machine
Install nodejs
A quick intro to unit testing
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
Functions
Scopes & Closures
Javascript Avanzado B
By rafinskipg
Javascript Avanzado B
JavaScript Avanzado.
- 813