JavaScript
Quick Recap
From class 1
Operators
Arithmetics
// + performs string or number addition
"hello" + 5 // hello5
// Rest of arithmetic operators perform number type casting
5 / '5' // 1
"hello" - 4 // NaN
// Unary + operator transforms value to number
+'-3' // -3
// The unary - operator transforms the value to number
// and performs a negation operation
-'3' // -3
[] + [] // '' [].toString()
[] - [] // 0 Number([])
Operators
Arithmetics
// Unary ! negates the boolean representation of the value
!false // true
!"hello" // false
// Falsey values are
NaN, undefined, 0, false, '', null
// ++ operator increments the value by one
var x = 5
var y = ++x // Increments and return the value
var z = y++ // Returns and increments the value
// -- operator decrements the value by one
Operators
Other
// typeof returns the type of the variable
typeof 2 // returns 'number'
typeof true // returns 'boolean'
// delete removes a property from an object
var a = { field: 'value' }
delete a.field // true
Operators
Comparission
// == performs a unestrict comparission
'5' == 5 // true
// === performs a strict comparission
'6' === 6 // false
Operators
spread operator
// can be used as an argument wherever
// array arguments are expected
const a = [1, 2, 3]
const b = [5, ...a, -3 ]
// Also in functions
function doSomething(first, ...rest) {}
doSomething(...a)
Operators
spread operator
// can be used as any pair
// key-value arguments
const a = {
property: 'one'
}
const b = {
...a,
other: 'test'
}
Operators
spread operator
// can be destructured
const a = [1,2,3]
const [first, ...rest] = a
const c = {
thing: 'test',
address: {
street: 'abc'
}
}
const {address, ...obj} = c
Closures & Scope
var thing = 5
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
The nature of types
2 built-in types
There are two built-in types in JS
Primitive types (boolean, number, string, null*, undefined*).
Reference types - Object, and the types that inherit from it. Fundamentals like Function and Error. Arrays. Regex. Date... Reference versions of primitives Number, Boolean, String.
The reference values are all objects
and primitive values are "autoboxed". Wrapped in a temporary reference object
var a = 'test'
'test'.contains('es')
var a = new Number(3)
var b = new Number(3)
a == b
3 == 3
Strings
'hello world'
`hello ${who}`
Strings can be created in different ways
"hello"
'hello'
typeof "hello" // string
typeof 'hello' // string
Template literals
var world = 'world'
var text = `hello
${world}`
Multiline strings the old way
var text = "this is a line \n" +
" this is another line"
The String global object is a constructor for strings, or a sequence of characters.
var a = new String('test')
typeof a // 'object'
var b = new String('test')
a == b // false because they are different objects
a == 'test' // true
a.valueOf() // 'test'
var c = {
valueOf: function() {
return 'test'
}
}
c == 'test'
String methods
var a = 'test'
a.charAt(0) // 't'
a.indexOf('est') // 1
a.length // 4
a.toUpperCase() // 'TEST'
'TEST'.toLowerCase() // test
'TEST'.split('') // ['T', 'E', 'S', 'T']
Operators, numbers && strings
miniexam
The nature of functions
Functions are "subprograms" that can be called.
They have arguments, a name , a function body and return a value
function doSomething(arg, arg2) {
console.log(arg, arg2)
}
Function expressions
var myFunction = function() { /* do something * /}
Function expressions can have a named or anonymous function
They are not hoisted
Can be used for recurssion
var factorial = function fac(n) {
return n < 2 ? 1 : n * fac(n - 1);
};
console.log(factorial(3));
Every function is a `Function` object
It inherints Function.prototype
function a() {}
// Function.prototype.length
a.length // 0
// Function.prototype.name
a.name // 'a'
// Function.prototype.apply()
// Function.prototype.call()
// Function.prototype.bind()
Understanding this
function f1() {
return this
}
// In a browser:
f1() === window;
// In Node:
f1() === global;
the value of `this` is determined by how a function is called
strict mode
function f1() {
'use strict';
return this
}
f1() // undefined
window.f1() // window
in strict mode, unless calling the method from an object, the value of this remains undefined
ES2015
arrow functions retain the context of the enclosing scope
Normal functions in JavaScript bind their own this value, however the this value used in arrow functions is actually fetched lexically from the scope it sits inside. It has no this, so when you use this you’re talking to the outer scope.
ES2015
function FooCtrl (FooService) {
this.foo = 'Hello';
FooService
.doSomething((response) => this.foo = response);
}
ES2015
var obj = {
bar: function() {
var x = function() {
return this
};
return x;
}
};
var c = obj.bar()
c() // window
arrow functions retain the context of the enclosing scope
ES2015
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
var c = obj.bar()
c() // obj
arrow functions retain the context of the enclosing scope
in object methods
var obj = {
name: 'pepe',
getName: function() {
return this.name
}
};
when called in object methods, this points to the object
the New keyword
function Person(name) {
this.name = name
}
const person = new Person('juan')
person.name // 'juan'
when using the "new" keyword, this gets bound to the new instance that is being created
changing this
function setName(name) {
this.name = name
}
var person = {
name: 'peter'
}
setName.call(person, 'parker')
the value of `this` is determined by how a function is called
It can be set during execution and can be different each time the function is called
Function.prototype.call()
function setName(name) {
this.name = name
}
var person = {}
setName.call(person, 'pedro')
Function.prototype.apply()
function setData(name, surname) {
this.name = name
this.surname = surname
}
var person = {}
setData.apply(person, ['pedro', 'blanco'])
c for commas
a for array
Function.prototype.bind()
function setData(name, surname) {
this.name = name
this.surname = surname
}
var person = {}
const setPeter = setData.bind(person, 'peter')
setPeter('parker')
setPeter('not parker')
Creates a new function bound to a context and some arguments
Exercise
create a setter function that receives one argument and sets the value to this.
Test calling it from different objects
Exercise
repeat the previous exercise but use .call and .apply to send various arguments to the function
function arguments
`arguments` is a reserved keyword that stands for an "array like" object (but not array) that represents the call arguments of the function
Function.prototype.apply() arguments
function setNameAndSurname(name, surname) {
this.name = name
this.surname = surname
}
var person = {
setData: function setData() {
setNameAndSurname.apply(this, arguments)
}
}
person.setData('hey', 'hello')
ES2015 (ES6) arguments
function setName(name, surname = 'pepe') {
this.name = name
this.surname = surname
}
Exercise
Create 2 functions that receives multiple arguments.
Call one function from the other using apply, and "arguments" reserved keyword
Exercise
With the previous functions. Bind the first to a fixed list of arguments
Imperative Vs Functional
Imperative
function simpleJoin(stringArray) {
var accumulator = ‘’
for (var i=0, l=stringArray.length; i < l; i++) {
accumulator = accumulator + stringArray[i]
}
return accumulator
}
functional
function simpleJoin(stringArray, acc = '') {
if(stringArray.length === 0) {
return acc
}
const [first, ...rest] = stringArray
return simpleJoin(rest, acc + first)
}
Array utilities
Array.prototype.map()
var newCars = cars.map(c => {
return {
...c,
clean: true
}
})
Array.prototype.filter()
var newCars = cars.filter(c => c.clean === true)
Array.prototype.find()
var newCar = cars.find(c => c.name === 'Volvo FTurbo mix')
Array.prototype.reduce()
var carsWeight = cars
.reduce((acc, next) => acc + next.weight, 0)
Some functional exercises
1 - Map over a list of numbers a return the square value
square([1,2,3])
// [ 1, 4, 9 ]
2 - Reduce the values of one array to get it's sum
sumAllElementsOfList([1,2,3])
// 6
3 - Do a function that receives an array of arrays as arguments. Return the reduced value of the sum of each
sumList([1,2,3,4], [4, 54, 212, 213], [123,2312, 231])
// 3160
Modules
JavaScript Modules
Modules
Modules divide programs into clusters of code that, by some criterion, belong together and may share an interface.
More on Modules
Why modules?
JavaScript shares the global scope. Namespace pollution can happen a lot of code uses global variables
Why modules?
We can separate pieces of code that share a similar purpose o functionality.
This is more obvious in the case of libraries (or modules)
functions can be used to create the isolated module
var names = ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday"];
function dayName(number) {
return names[number];
}
dayName(0) // "Sunday"
functions are the only thing that will create a new scope, so functions are needed to create a module
var dayName = function() {
var names = ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return function(number) {
return names[number];
};
}();
dayName(0) // "Sunday"
Objects as interfaces
var weekDay = function() {
var names = ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
return {
name: function(number) { return names[number]; },
number: function(name) { return names.indexOf(name); }
};
}();
Allows to expose certain methods or properties and leave the rest hidden from the outside world
Objects as interfaces
(function(exports) {
var names = ["Sunday", "Monday",
"Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
exports.name = function(number) {
return names[number];
};
exports.number = function(name) {
return names.indexOf(name);
};
})(this.weekDay = {});
For larger modules we can use another pattern
Modules internal state
var counterModule = (function() {
let counter = 0;
const increment = () => ++counter;
const decrement = () => --counter;
return {
increment,
decrement
}
})()
Modules can have it's internal state and manage it without conflicting with the global state
Standard module patterns
CommonJS, AMD & ES6 Modules
AMD
Asynchronous Module Definition
define('myModule',
['math', 'graph'],
function ( math, graph ) {
return {
plot: function(x, y){
return graph.drawPie(math.randomGrid(x,y));
}
}
};
});
Defined for the browser, with an asynchronous behaviour in mind
CommonJS
function doSomething() {
// Do
}
function doAnother() {
// Do
}
module.exports = {
doSomething: doSomething,
doAnother: doAnother
}
CommonJS
var myModule = require('./myModule')
myModule.doSomething();
myModule.doAnother();
Can this be used in the browser?
ES6
export const list = [1, 2, 3]
export const doSomething = (cb) => list.map(cb)
export function doAnother (cb) {
return list.filter(cb)
}
export default function() {
console.log('a')
}
With ES6 JavaScript for the first time has a built-in module system.
Each file is a module
ES6
import * as myModule from './mymodule'
import { doSomething, doAnother } from './mymodule'
import mything from './anothermodule'
Importing modules
https://github.com/rafinskipg/test-setup-webpack
Modules
Exercises
0 - Start a new project
$> mkdir usersManagementApplication
$> cd usersManagementApplication
$> npm init
// create main.js
// launch with node main.js
1 - Create a users module
Use CommonJS for native node JS support.
- The module holds the internal state of users.
- It exports a "find" method that helps you find a user by name
- It exports a "update" method that updates the value of the user in the internal state
- It exports a "get" method that returns the list of users
2 - Add ES6 support to your project
npm install --save-dev babel-{core,loader,preset-es2015-native-modules} webpack
https://github.com/rafinskipg/test-setup-webpack
3 -Push your code to your preferred version control system.
We are going to use it later
(Github, Gitlab, bitbucket, dropbox? zip? email to a friend? print in paper?)
Objects
what is an object?
An object is a "box" that provides an interface for abstracting logic and hiding complexity.
objects in JS
They have methods.
var beers = {
amount: 50,
drinkBeer: function() { --this.amount },
buyBeer: function() { ++this.amount }
}
Methods are properties that hold a function value
Sharing methods and unique context
function collide(wall) {
console.log(`the person ${this.name}
collided with the ${wall}`)
}
const personOne = {
name : 'petorski',
collide: collide
}
const personTwo = {
name : 'markantu',
collide: collide
}
personOne.collide('dirty ass')
personTwo.collide('green wall of doom')
Prototype
Almost all objects have a prototype that they use for inheriting methods and properties
var a = {}
a.toString
we call JavaScript a prototypal inheritance language
The prototypal inheritance forms a tree shaped structure.
Since everything "inherits" from Object.prototype
different branches
Functions derive from Function.prototype
Arrays from Array.prototype
Normal objects from Object.prototype
Object constructors
As we have seen we can create new instances of objects with function constructors
function Engine() {
this.started = false
}
function Car(model) {
this.model = model
this.engine = new Engine()
}
var tesla = new Car('tesla')
constructors prototype
we can define the prototype of the object constructors
Car.prototype.startEngine = function() {
this.engine.started = true
}
Car.prototype.stopEngine = function() {
this.engine.started = false
}
var tesla = new Car('tesla')
constructors prototype
the prototype property will be the prototype of instances created through it but is not its own prototype.
Object.getPrototypeOf(tesla)
{startEngine: ƒ, stopEngine: ƒ, constructor: ƒ}
Object.getPrototypeOf(Car)
ƒ () { [native code] }
Constructors owns prototype is the Function one
constructors prototype
Changing a constructors prototype is going to change all the instances at the same time
// tesla
Car.prototype.color = 'red'
tesla.color // red
Prototypes are objects, they are shared by all the instances by reference.
Be carefull
Accessing objects methods and properties
As we said, the prototype forms a tree of "inheritance", and for knowing which properties has an object, JavaScript does this in this way:
1 - It checks the object methods
2 - It checks it's prototype methods
3 - It checks it's prototype's prototype methods
... repeat
For performance, avoid long prototype chains
We can "extend" the language
Mutating Object.prototype can give us some good tools
Object.prototype.jotica = function() {
console.log('La virgen del pilar diceeeeee')
}
var a = {}
a.jotica()
Exercise
Mutate Array.prototype to:
Create a method that returns the first element of the array
Create a method that returns the last element of the array
mutating is slow
why?
Access to prototype is fast, and often objects are predictable. In that case the JIT compiler stores the instructions to reuse them.
mutating is slow
why?
But when we mutate a prototype, all the objects that used that prototype have to be checked again by the JIT compiler.
Also... all the code the object flows through has to be re-checked, because the optimization relies in the form of the prototypes
Super exercise
Clone
https://github.com/rafinskipg/test-object-prototype
JavaScript Avanzado - Dia 2
By rafinskipg
JavaScript Avanzado - Dia 2
Segunda clase del curso de javascript avanzado
- 516