JavaScript Avanzado

Adolfo Sanz De Diego

Octubre 2015

1 Acerca de

1.1 Autor

1.2 Licencia

1.3 Ejemplos

2 JavaScript

2.1 Historia

2.2 El lenguaje

3 Orientación a objetos

3.1 ¿Qué es un objeto?

3.2 Propiedades

objeto.nombre === objeto[nombre] // true
var objeto = {};
objeto.nuevaPropiedad = 1; // añadir
delete objeto.nuevaPropiedad; // eliminar

3.3 Objeto iniciador

var objeto = {
  nombre: "Adolfo",
  twitter: "@asanzdiego"
};

3.4 Función constructora

function Persona(nombre, twitter) {
  this.nombre = nombre;
  this.twitter = twitter;
};
var objeto = new Persona("Adolfo", "@asanzdiego");

3.5 Prototipos

// Falla en Opera o IE <= 8
Object.getPrototypeOf(objeto);

// No es estandar y falla en IE
objeto.__proto__;

3.6 Eficiencia

function ConstructorA(p1) {
  this.p1 = p1;
}

// los métodos los ponenmos en el prototipo
ConstructorA.prototype.metodo1 = function() {
  console.log(this.p1);
};

3.7 Herencia

function ConstructorA(p1) {
  this.p1 = p1;
}

function ConstructorB(p1, p2) {
  // llamamos al super para que no se pierda p1.
  ConstructorA.call(this, p1);
  this.p2 = p2;
}

// Hacemos que B herede de A
// Prototipo de Función Constructora B apunta al
// Prototipo de Función Constructora A
ConstructorB.prototype = Object.create(ConstructorA.prototype);

3.8 Cadena de prototipos

3.9 Cadena de prototipos de la instancia

instanciaB.__proto__ == ConstructorB.prototype // true
instanciaB.__proto__.__proto__ == ConstructorA.prototype // true
instanciaB.__proto__.__proto__.__proto__ == Object.prototype // true
instanciaB.__proto__.__proto__.__proto__.__proto__ == null // true

3.10 Cadena de prototipos de la función constructora

expect(ConstructorB.__proto__).toEqual(Function.prototype);
expect(ConstructorB.__proto__.__proto__).toEqual(Object.prototype);
expect(ConstructorB.__proto__.__proto__.__proto__).toEqual(null);

3.11 Esquema prototipos

Esquema prototipos

3.12 Operador instanceof

instanciaB instanceof ConstructorB; // true
instanciaB instanceof ConstructorA; // true
instanciaB instanceof Object; // true

3.13 Extensión

String.prototype.hola = function() {
  return "Hola "+this;
}

"Adolfo".hola(); // "Hola Adolfo"

3.14 Propiedades y métodos estáticos

function ConstructorA() {

  ConstructorA.propiedadEstatica = "propiedad estática";
}

ConstructorA.metodoEstatico = function() {
  console.log("método estático");
}

3.15 Propiedades y métodos privados

function ConstructorA(privada, publica) {
  var propiedadPrivada = privada;
  this.propiedadPublica = publica;
  var metodoPrivado = function() {
    console.log("-->propiedadPrivada", propiedadPrivada);
  }
  this.metodoPublico = function() {
    console.log("-->propiedadPublica", this.propiedadPublica);
    metodoPrivado();
  }
}

3.16 Polimorfismo

4 Técnicas avanzadas

4.1 Funciones

4.2 This

var nombre = "Laura";

var alba = {
  nombre: "Alba",
  saludo: function() {
    return "Hola "+this.nombre;
  }
}

alba.saludo(); // Hola Alba

var fn = alba.saludo;

fn(); // Hola Laura

4.3 call y apply

fn.call(thisArg [, arg1 [, arg2 [...]]])
fn.apply(thisArg [, arglist])

4.4 Número variable de argumentos

4.5 Arguments

function echoArgs() {
  console.log(arguments[0]); // Adolfo
  console.log(arguments[1]); // Sanz
}
echoArgs("Adolfo", "Sanz");

4.6 Declaración de funciones

function holaMundo1() {
  console.log("Hola Mundo 1");
}
holaMundo1();

var holaMundo2 = function() {
  console.log("Hola Mundo 2");
}
holaMundo2();

4.7 Transfiriendo funciones a otras funciones

function saluda() {
  console.log("Hola")
}
function ejecuta(func) {
  func()
}
ejecuta(saluda);

4.8 Funciones anónimas

function(nombre) {
  console.log("Hola "+nombre);
}
function saludador(nombre) {
  return function() {
    console.log("Hola "+nombre);
  }
}

var saluda = saludador("mundo");
saluda(); // Hola mundo

4.9 Funciones autoejecutables

(function(nombre) {
  console.log("Hola "+nombre);
})("mundo")

4.10 Clousures

function creaSumador(x) {
  return function(y) {
    return x + y;
  };
}

var suma5 = creaSumador(5);
var suma10 = creaSumador(10);

console.log(suma5(2));  // muestra 7
console.log(suma10(2)); // muestra 12

4.11 El patrón Modulo

miModulo = (function() {

  var propiedadPrivada;

  function metodoPrivado() { };

  // API publica
  return {
    metodoPublico1: function () {
    },

    metodoPublico2: function () {
    }
  }
}());

4.12 Eficiencia

miModulo = (function(window, undefined) {

  // El código va aquí

})( window );

4.13 El patrón Modulo Revelado

miModulo = (function() {

  function metodoA() { };

  function metodoB() { };

  function metodoC() { };

  // API publica
  return {
    metodoPublico1: metodoA,
    metodoPublico2: metodoB
  }
}());

4.14 Espacios de nombres

miBiblioteca = miBiblioteca || {};

miBiblioteca.seccion1 = miBiblioteca.seccion1 || {};

miBiblioteca.seccion1 = {
  priopiedad: p1,
  metodo: function() { },
};

miBiblioteca.seccion2 = miBiblioteca.seccion2 || {};

miBiblioteca.seccion2 = {
  priopiedad: p2,
  metodo: function() { },
};

miBiblioteca = miBiblioteca || {};

(function(namespace) {

  var propiedadPrivada = p1;

  namespace.propiedadPublica = p2;

  var metodoPrivado = function() { };

  namespace.metodoPublico = function() { };

}(miBiblioteca));

5 Document Object Model

5.1 ¿Qué es DOM?

5.2 Tipos de nodos

5.3 Recorrer el DOM

getElementById(id)
getElementsByName(name)
getElementsByTagName(tagname)
getElementsByClassName(className)
getAttribute(attributeName)
querySelector(selector)
querySelectorAll(selector)

5.4 Manipular el DOM

createElement(tagName)
createTextNode(text)
createAttribute(attributeName)
appendChild(node)
insertBefore(newElement, targetElement)
removeAttribute(attributename)
removeChild(childreference)
replaceChild(newChild, oldChild)

5.5 Propiedades Nodos

attributes[]
className
id
innerHTML
nodeName
nodeValue
style
tabIndex
tagName
title
childNodes[]
firstChild
lastChild
previousSibling
nextSibling
ownerDocument
parentNode

6 Librerías y Frameworks

6.1 jQuery

// Vanilla JavaScript
var elem = document.getElementById("miElemento");

//jQuery
var elem = $("#miElemento");  

6.2 jQuery UI & Mobile

6.3 Frameworks CSS

6.4 MVC en el front

6.5 NodeJS

6.6 Automatización de tareas

6.7 Gestión de dependencias

6.8 Aplicaciones de escritorio multiplataforma

6.9 Aplicaciones móviles híbridas

6.10 WebComponents

6.11 Otros

7 Eventos

7.1 El patrón PubSub

var EventBus = {
  topics: {},

  subscribe: function(topic, listener) {
    if (!this.topics[topic]) this.topics[topic] = [];
    this.topics[topic].push(listener);
  },

  publish: function(topic, data) {
    if (!this.topics[topic] || this.topics[topic].length < 1) return;
    this.topics[topic].forEach(function(listener) {
      listener(data || {});
    });
  }
};
EventBus.subscribe('foo', alert);
EventBus.publish('foo', 'Hello World!');
var Mailer = function() {
  EventBus.subscribe('order/new', this.sendPurchaseEmail);
};

Mailer.prototype = {
  sendPurchaseEmail: function(userEmail) {
    console.log("Sent email to " + userEmail);
  }
};
var Order = function(params) {
  this.params = params;
};

Order.prototype = {
  saveOrder: function() {
    EventBus.publish('order/new', this.params.userEmail);
  }
};
var mailer = new Mailer();
var order = new Order({userEmail: 'john@gmail.com'});
order.saveOrder();
"Sent email to john@gmail.com"

7.2 Principales eventos

Evento Descripción
onblur Un elemento pierde el foco
onchange Un elemento ha sido modificado
onclick Pulsar y soltar el ratón
ondblclick Pulsar dos veces seguidas con el ratón
Evento Descripción
onfocus Un elemento obtiene el foco
onkeydown Pulsar una tecla y no soltarla
onkeypress Pulsar una tecla
onkeyup Soltar una tecla pulsada
onload Página cargada completamente
Evento Descripción
onmousedown Pulsar un botón del ratón y no soltarlo
onmousemove Mover el ratón
onmouseout El ratón "sale" del elemento
onmouseover El ratón "entra" en el elemento
onmouseup Soltar el botón del ratón
Evento Descripción
onreset Inicializar el formulario
onresize Modificar el tamaño de la ventana
onselect Seleccionar un texto
onsubmit Enviar el formulario
onunload Se abandona la página

7.3 Suscripción

var windowOnLoad = function(e) {
  console.log('window:load', e);
};

window.addEventListener('load', windowOnLoad);

window.removeEventListener('load', windowOnLoad);

7.4 Eventos personalizados

var event = new Event('build');

elem.addEventListener('build', function (e) { ... }, false);
var event = new CustomEvent('build', { 'detail': detail });

elem.addEventListener('build', function (e)  {
  log('The time is: ' + e.detail);
}, false);

7.5 Disparar un evento

function simulateClick() {
  var event = new MouseEvent('click');
  var element = document.getElementById('id');
  element.dispatchEvent(event);
}

7.6 Propagación

               1              2
              | |            / \
+-------------| |------------| |-------------+
| DIV1        | |            | |             |
|   +---------| |------------| |---------+   |
|   | DIV2    | |            | |         |   |
|   |   +-----| |------------| |-----+   |   |
|   |   | A   \ /            | |     |   |   |
|   |   +----------------------------+   |   |
|   +------------------------------------+   |
|           FASE DE        FASE DE           |
|           CAPTURA        BURBUJA           |
|          DE EVENTOS     DE EVENTOS         |
+--------------------------------------------+
// en fase de CAPTURA
addEventListener("eventName",callback, true);

// en fase de BURBUJA
addEventListener("eventName",callback, false); // por defecto
// detiene la propagación del evento
event.stopPropagation();

// elimina las acciones por defecto (ejemplo: abrir enlace)
event.preventDefault();

8 WebSockets

8.1 ¿Qué son los WebSockets?

8.2 Socket.IO

9 AJAX

9.1 ¿Qué es AJAX?

9.2 Tecnologías AJAX

9.3 ¿Qué es el XMLHttpRequest?

9.4 Ejemplo

var http_request = new XMLHttpRequest();
var url = "http://example.net/jsondata.php";

// Descarga los datos JSON del servidor.
http_request.onreadystatechange = handle_json;
http_request.open("GET", url, true);
http_request.send(null);

function handle_json() {
  if (http_request.status == 200) {
    var json_data = http_request.responseText;
    var the_object = eval("(" + json_data + ")");
  } else {
    alert("Ocurrio un problema con la URL.");
  }
}

10 JSON

10.1 ¿Qué es JSON?

10.2 Parse

miObjeto = eval('(' + json_datos + ')');

10.3 Ejemplo

{
    curso: "AJAX y jQuery",
    profesor: "Adolfo",
    participantes: [
        { nombre: "Isabel", edad: 35 },
        { nombre: "Alba", edad: 15 },
        { nombre: "Laura", edad: 10 }
    ]
}

10.4 JSONP

10.5 CORS

Access-Control-Allow-Origin: http://dominio-permitido.com

11 APIs REST

11.1 ¿Qué es un API REST?

11.2 ¿Por qué REST?

11.3 Ejemplo API

11.4 Errores HTTP

12 Gestión de dependencias

12.1 AMD

12.2 RequireJS

<!DOCTYPE html>
<html>
    <head>
        <title>Page 1</title>
        <script data-main="js/index" src="js/lib/require.js"></script>
    </head>
    <body>
        <h1>Hola Mundo</h1>
    </body>
</html>
requirejs(['./common'], function (common) {
    requirejs(['app/main']);
});
define(function (require) {
    var $ = require('jquery');
    var persona = require('./persona');

    $('h1').html("Hola requery.js");

    var p = new persona("Adolfo", 30);
    p.saludar();
});
define(function () {

  var Persona = function(nombre, edad) {

      this.nombre = nombre;

      Persona.prototype.saludar = function() {
          alert("Hola, mi nombre es " + this.nombre);
      };
  }

  return Persona;
});

12.3 CommonJS

12.4 Browserify

npm install -g browserify
npm install
{
  "name": "browserify-example",
  "version": "1.0.0",
  "dependencies": {
    "jquery": "^2.1.3"
  }
}
browserify js/main.js -o js/bundle.js
<!doctype html>
<html>
  <head>
    <title>Browserify Playground</title>
  </head>
  <body>
    <h1>Hola Mundo</h1>
    <script src="js/bundle.js"></script>
  </body>
</html>
var $ = require('jquery');
var persona = require('./persona');

$('h1').html('Hola Browserify');

var p = new persona("Adolfo", 30);
p.saludar();
var Persona = function(nombre, edad) {

    this.nombre = nombre;

    Persona.prototype.saludar = function() {
        alert("Hola, mi nombre es " + this.nombre);
    };
}

module.exports = Persona;

12.5 ECMAScript 6

13 ES6

13.1 Como usarlo hoy

13.2 Función Arrow

// ES5
var data = [{...}, {...}, {...}, ...];  
data.forEach(function(elem){  
    console.log(elem)
});

13.3 Función Arrow

//ES6
var data = [{...}, {...}, {...}, ...];  
data.forEach(elem => {  
    console.log(elem);
});
// ES5
var miFuncion = function(num1, num2) {  
    return num1 + num2;
}
// ES6
var miFuncion = (num1, num2) => num1 + num2;  

13.4 This

//ES5
var objEJ5 = {
  data : ["Adolfo", "Isabel", "Alba"],
  duplicar : function() {
    var that = this;
    this.data.forEach(function(elem){
        that.data.push(elem);
    });
    return this.data;
  }
}
//ES6
var objEJ6 = {
  data : ["Adolfo", "Isabel", "Alba"],
  duplicar : function() {
    this.data.forEach((elem) => {
        this.data.push(elem);
    });
    return this.data;
  }
}

13.5 Definición de Clases

//ES5
var Shape = function (id, x, y) {
    this.id = id;
    this.move(x, y);
};
Shape.prototype.move = function (x, y) {
    this.x = x;
    this.y = y;
};
//ES6
class Shape {
    constructor (id, x, y) {
        this.id = id
        this.move(x, y)
    }
    move (x, y) {
        this.x = x
        this.y = y
    }
}

13.6 Herencia de Clases

//ES5
var Rectangle = function (id, x, y, width, height) {
    Shape.call(this, id, x, y);
    this.width  = width;
    this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var Circle = function (id, x, y, radius) {
    Shape.call(this, id, x, y);
    this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
//ES6
class Rectangle extends Shape {
    constructor (id, x, y, width, height) {
        super(id, x, y)
        this.width  = width
        this.height = height
    }
}
class Circle extends Shape {
    constructor (id, x, y, radius) {
        super(id, x, y)
        this.radius = radius
    }
}

13.7 let

//ES5
(function() {
    console.log(x); // x no está definida aún.
    if(true) {
        var x = "hola mundo";
    }
    console.log(x);
    // Imprime "hola mundo", porque "var"
    // hace que sea global a la función;
})();
//ES6
(function() {
    if(true) {
        let x = "hola mundo";
    }
    console.log(x);
    //Da error, porque "x" ha sido definida dentro del "if"
})();

13.8 Scopes

//ES5
(function () {
    var foo = function () { return 1; }
    foo() === 1;
    (function () {
        var foo = function () { return 2; }
        foo() === 2;
    })();
    foo() === 1;
})();
//ES6
{
    function foo () { return 1 }
    foo() === 1
    {
        function foo () { return 2 }
        foo() === 2
    }
    foo() === 1
}

13.9 const

//ES6
(function() {
    const PI;
    PI = 3.15;
    // ERROR, porque ha de asignarse un valor en la declaración
})();
//ES6
(function() {
    const PI = 3.15;
    PI = 3.14159;
    // ERROR de nuevo, porque es de sólo-lectura
})();

13.10 Template Strings

//ES6
let nombre1 = "JavaScript";  
let nombre2 = "awesome";  
console.log(`Sólo quiero decir que ${nombre1} is ${nombre2}`);  
// Solo quiero decir que JavaScript is awesome
//ES5
var saludo = "ola " +  
"que " +
"ase ";
//ES6
var saludo = `ola  
que  
ase`;

13.11 Destructuring

//ES6
var [a, b] = ["hola", "mundo"];  
console.log(a); // "hola"  
console.log(b); // "mundo"
//ES6
var obj = { nombre: "Adolfo", apellido: "Sanz" };  
var { nombre, apellido } = obj;  
console.log(nombre); // "Adolfo"  
console.log(apellido); // "Sanz"  
//ES6
var foo = function() {  
    return ["180", "78"];
};
var [estatura, peso] = foo();  
console.log(estatura); //180
console.log(peso); //78

13.12 Parámetros con nombre

//ES5
function f (arg) {
    var name = arg[0];
    var val  = arg[1];
    console.log(name, val);
};
function g (arg) {
    var n = arg.name;
    var v = arg.val;
    console.log(n, v);
};
function h (arg) {
    var name = arg.name;
    var val  = arg.val;
    console.log(name, val);
};
f([ "bar", 42 ]);
g({ name: "foo", val:  7 });
h({ name: "bar", val: 42 });
//ES6
function f ([ name, val ]) {
    console.log(name, val)
}
function g ({ name: n, val: v }) {
    console.log(n, v)
}
function h ({ name, val }) {
    console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val:  7 })
h({ name: "bar", val: 42 })

13.13 Resto parámetros

//ES5
function f (x, y) {
    var a = Array.prototype.slice.call(arguments, 2);
    return (x + y) * a.length;
};
f(1, 2, "hello", true, 7) === 9;
//ES6
function f (x, y, ...a) {
    return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9

13.14 Valores por defecto

//ES5
function(valor) {  
    valor = valor || "foo";
}

13.15 Valores por defecto

//ES6
function(valor = "foo") {...};  

13.16 Exportar módulos

//ES6

// lib/math.js
export function sum (x, y) { return x + y }
export function div (x, y) { return x / y }
export var pi = 3.141593

13.17 Importar módulos

//ES6

// someApp.js
import * as math from "lib/math"
console.log("2π = " + math.sum(math.pi, math.pi))

// otherApp.js
import { sum, pi } from "lib/math"
console.log("2π = " + sum(pi, pi))

13.18 Generadores

//ES6
function *soyUnGenerador(i) {  
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

var gen = soyUnGenerador(1);  
console.log(gen.next());  
//  Object {value: 2, done: false}
console.log(gen.next());  
//  Object {value: 3, done: false}
console.log(gen.next());  
//  Object {value: 4, done: false}
console.log(gen.next());  
//  Object {value: undefined, done: true}

13.19 Set

//ES6
let s = new Set()
s.add("hello").add("goodbye").add("hello")
s.size === 2
s.has("hello") === true
for (let key of s.values()) { // insertion order
  console.log(key)
}

13.20 Map

//ES6
let m = new Map()
m.set("hello", 42)
m.set(s, 34)
m.get(s) === 34
m.size === 2
for (let [ key, val ] of m.entries()) {
  console.log(key + " = " + val)
}

13.21 Nuevos métodos en String

//ES6
"hello".startsWith("ello", 1) // true
"hello".endsWith("hell", 4)   // true
"hello".includes("ell")       // true
"hello".includes("ell", 1)    // true
"hello".includes("ell", 2)    // false

13.22 Nuevos métodos en Number

//ES6
Number.isNaN(42) === false
Number.isNaN(NaN) === true
Number.isSafeInteger(42) === true
Number.isSafeInteger(9007199254740992) === false

13.23 Proxies

//ES6
let target = {
    foo: "Welcome, foo"
}
let proxy = new Proxy(target, {
    get (receiver, name) {
        return name in receiver ? receiver[name] : `Hello, ${name}`
    }
})
proxy.foo   === "Welcome, foo"
proxy.world === "Hello, world"

13.24 Internacionalization

//ES6
var i10nUSD = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })
var i10nGBP = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" })
i10nUSD.format(100200300.40) === "$100,200,300.40"
i10nGBP.format(100200300.40) === "£100,200,300.40"
//ES6
var i10nEN = new Intl.DateTimeFormat("en-US")
var i10nDE = new Intl.DateTimeFormat("de-DE")
i10nEN.format(new Date("2015-01-02")) === "1/2/2015"
i10nDE.format(new Date("2015-01-02")) === "2.1.2015"

13.25 Promesas

//ES6
var promise = new Promise(function(resolve, reject) {

  var todoCorrecto = true; // o false dependiendo de como ha ido

  if (todoCorrecto) {
    resolve("Promesa Resuelta!");
  } else {
    reject("Promesa Rechazada!");
  }
});
//ES6

// llamamos el metodo 'then' de la promesa
// con 2 callbacks (resolve y reject)
promise.then(function(result) {
  console.log(result); // "Promesa Resuelta!"
}, function(err) {
  console.log(err); // Error: "Promesa Rechazada!"
});
//ES6

// podemos también llamar al 'then' con el callback 'resolve'
// y luego al 'catch' con el callback 'reject'
promise.then(function(result) {
  console.log(result); // "Promesa Resuelta!"
}).catch(function(err) {
  console.log(err); // Error: "Promesa Rechazada!"
});
//ES6

Promise.all([promesa1,promesa2]).then(function(results) {
  console.log(results); // cuando todas las promesas terminen
}).catch(function(err) {
  console.log(err); // Error: "Error en alguna promesa!"
});
//ES6

Promise.race([promesa1,promesa2]).then(function(firstResult) {
  console.log(firstResult); // cuando termine la primera
}).catch(function(err) {
  console.log(err); // Error: "Error en alguna promesa!"
});

14 Enlaces

14.1 General (ES)

14.2 General (EN)

14.3 Orientación Objetos (ES)

14.4 Orientación Objetos (EN)

14.5 Técnicas avanzadas (ES)

14.6 DOM (ES)

14.7 DOM (EN)

14.8 Frameworks (ES)

14.9 Frameworks (EN)

14.10 Eventos (ES)

14.11 Eventos (EN)

14.12 WebSockets (ES)

14.13 WebSockets (EN)

14.14 AJAX, JSON, REST (ES)

14.15 ES6 (ES)

14.16 ES6 (EN)