SlideShare a Scribd company logo
1 of 601
Download to read offline
Javascript para Profesionales



made with love by Redradix (www.redradix.com)
Fundamentos
Objetos
!

!

Conjunto de propiedades propias + heredadas
de otro objeto (prototipos)
¡Qué no cunda el pánico!
Objetos
!

Dinámicos

!

Set de strings

var obj = {};
obj.nuevaPropiedad = 1;
delete obj.nuevaPropiedad;

var strset = {
hola: true,
adios: true
};
"hola" in strset;
Objetos
!

Referencias

var p1 = {x: 1},
p2 = p1;
p1 === p2; // true
p1.x = 5;
p2.x; // 5

!

!

Todo son objetos excepto: strings, números,
booleans, null o undefined
Strings, números y booleans se comportan como
objetos inmutables
Objetos
!

!

Ciudadanos de primer
orden

Contener valor
primitivo u otros
objetos. Incluyendo
funciones.

(function (obj) {
return {b: 2};
})({a: 1});

var obj = {
f: function() {
console.log("hola");
}
};
obj.f();
Objetos
!

Literales

{
un: "objeto",
literal: true

- clase: Object
- sencillos y ligeros

!

Construidos
- clase: prototype
- constructor

};

new NombreDeUnaFuncion();
Clases
!

Pueden entenderse como:
−

Tipo (jerárquico) de datos
−

Aquí no

−

Categoría de objetos con la misma estructura

−

Al grano: objetos con el mismo prototipo.
Clases
Si esto es un “punto”

var point = {x: 0, y: 0};

Y esto es otro “punto”

var point2 = {x: 5, y: 5};

¿Qué es esto?

var what = {x: 10, y: 10};

¿Y esto?

var isit = {x: -10, y: -20};
Mensajes
• Teniendo:
var obj = {
nombre: "Pepito",
saludo: function () {
return "Hola, Mundo!";
}
};

• ¿Que significa esto?
obj.nombre;
Mensajes
• Teniendo:
var obj = {
nombre: "Pepito",
saludo: function () {
return "Hola, Mundo!";
}
};

• ¿Y esto?
obj.saludo;
Mensajes
• Teniendo:
var obj = {
nombre: "Pepito",
saludo: function () {
return "Hola, Mundo!";
}
};

• ¿Y esto otro? (¡cuidado!)
obj[“saludo”]();
Mensajes
• Teniendo:
var obj = {
nombre: "Pepito",
saludo: function () {
return "Hola, Mundo!";
}
};

• ¿Es lo mismo?
var fn = obj["saludo"];
fn();
Mensajes
• Teniendo:
var obj = {
nombre: "Pepito",
saludo: function () {
return "Hola, Mundo!";
}
};

• ¡NO es no mismo!
var fn = obj["saludo"];
fn();
Mensajes
• Una función se puede ejecutar de 4 maneras:
- Invocando directamente la función
(function() { alert("Hey!"); })();

- Enviando un mensaje a un objeto (método)
objeto.metodo();

- Como constructor
new MiConstructor();

- Indirectamente, a través de call(...)
fn.call({}, "param");

y

apply(...)
Mensajes
- Invocando directamente la función
(function() { alert("Hey!"); })();

- Enviando un mensaje a un objeto (método)
objeto.metodo();
Mensajes
Un mensaje se envía a un receptor
var obj = {};
obj.toString(); // [object Object]
"hola don Pepito".toUpperCase();
Mensajes
Un mensaje se envía a un receptor
var obj = {};
obj.toString(); // [object Object]
"hola don Pepito".toUpperCase();
Mensajes
La sintaxis es engañosa
var obj = {
coleccion: ["uno", "dos", "tres"],
metodo: function() {
return "Hola, Mundo!";
}
};

obj.coleccion[1];

vs.

obj.metodo();
Mensajes
var fn = obj.metodo;
fn();

obj.metodo();
Mensajes
var fn = obj.metodo;
fn();

- Accede a la propiedad
“metodo” de obj

- Supongo que es una función
y la invoco

obj.metodo();
Mensajes
var fn = obj.metodo;
fn();

obj.metodo();

- Accede a la propiedad

- Envía el mensaje “metodo” a

- Supongo que es una función

- Si existe, obj se encarga de

“metodo” de obj
y la invoco

obj

ejecutar la función
Mensajes
var fn = obj.metodo;
fn();

obj.metodo();

- Accede a la propiedad

- Envía el mensaje “metodo” a

- Supongo que es una función

- Si existe, obj se encarga de

- NO HAY RECEPTOR

- obj ES EL RECEPTOR

“metodo” de obj
y la invoco

obj

ejecutar la función
Mensajes
Un error típico:
$("#elemento").click(objeto.clickHandler);
Mensajes
Un error típico:
$("#elemento").click(objeto.clickHandler);

• Lo que se intenta decir:
- “Al hacer click sobre #elemento, envía el mensaje
clickHandler a objeto”
Mensajes
Un error típico:
$("#elemento").click(objeto.clickHandler);

• Lo que se intenta decir:
- “Al hacer click sobre #elemento, envía el mensaje
clickHandler a objeto”

• Lo que se dice en realidad:
- “Accede al valor de la propiedad clickHandler de objeto y
ejecútalo al hacer click sobre #elemento”
El receptor: ...
¿Por qué tanto lío con el receptor del mensaje?
El receptor: this
¿Por qué tanto lío con el receptor del mensaje?
- ¡El receptor es this!
- La metáfora mensaje/receptor aclara su (escurridizo)
significado
El receptor: this
this = “el receptor de este mensaje”
var nombre = "Sonia";
var obj = {
nombre: "Pepito",
saludo: function() {
alert("hola " + this.nombre);
}
}
obj.saludo();
El receptor: this
this

• Su significado es dinámico
• Se decide en el momento (y según la manera) de
ejecutar la función

• Se suele llamar “el contexto de la función”
• Cuando no hay receptor, apunta al objeto global
El receptor: this
Cuando no hay receptor, es el objeto global
var nombre = "Sonia"
var obj = {
nombre: "Pepito",
saludo: function() {
alert("hola " + this.nombre)
}
}
var fn = obj["saludo"];
fn();
El receptor: this
Su valor es dinámico
var obj = {
nombre: "Pepito",
saludo: function() {
alert("hola " + this.nombre);
}
};
var maria = {
nombre: "María"
};
maria.saludo = obj.saludo;
maria.saludo();
El receptor: this
Semánticamente, es como un parámetro oculto
function ([this]) {
alert("hola " + this.nombre);
}

que el receptor se encargara de proveer
obj.saludo(); => saludo([obj]);
El receptor: this
Semánticamente, es como un parámetro oculto
var nombre = "Sonia";
var obj = {
nombre: "Pepito",
saludo: function() {
var saludo_fn = function() {
alert("hola " + this.nombre);
};
saludo_fn();
}
};
obj.saludo();
El receptor: this
Semánticamente, es como un parámetro oculto
var nombre = "Sonia";
var obj = {
nombre: "Pepito",
saludo: function([this]) {
var saludo_fn = function([this]) {
alert("hola " + this.nombre);
};
saludo_fn([objeto global]);
}
};
obj.saludo([obj]);
El receptor: this
Semánticamente, es como un parámetro oculto
var nombre = "Sonia";
var obj = {
nombre: "Pepito",
saludo: function([this]) {
var saludo_fn = function([this]) {
alert("hola " + this.nombre);
};
saludo_fn([objeto global]);
}
};
obj.saludo([obj]);
El receptor: this
Es decir:

• Cada función tiene su propio this
• Una función anidada en otra NO comparte el receptor
• El valor de this depende de la invocación, NO de la
definición (no se clausura)
El receptor: this
Otro error común:
var obj = {
clicks: 0,
init: function() {
$("#element").click(function() {
this.clicks += 1;
});
}
};
obj.init();
El receptor: this
Otro error común:
var obj = {
clicks: 0,
init: function([this]) {
$("#element").click(function([this]) {
this.clicks += 1;
});
}
};
obj.init([obj]);
El receptor: this
Una posible solución (aunque no la mejor):
var obj = {
clicks: 0,
init: function() {
var that = this;
$("#element").click(function() {
that.clicks += 1;
});
}
};
obj.init();
Repaso: Mensajes
• Una función se puede ejecutar de 4 maneras:
- Invocando directamente la función
(function() { alert("Hey!"); })();

- Enviando un mensaje a un objeto (método)
objeto.metodo();

- Como constructor
new MiConstructor();

- Indirectamente, a través de call(...)
fn.call({}, "param");

y

apply(...)
Repaso: Mensajes
Una función se puede ejecutar de 4 maneras:
Invocando directamente la función
Enviando un mensaje a un objeto (método)
Como constructor

- Indirectamente, a través de call(...)
fn.call({}, "param");

y

apply(...)
El receptor: this
• Las funciones son objetos
• Se pueden manipular como cualquier otro objeto
- Asignar valores a propiedades
- Pasar como parámetros a otras funciones
- Ser el valor de retorno
- Guardarse en variables u otros objetos

• Tienen métodos
var fn = function() { alert("Hey!"); };
fn.toString();
El receptor: this
• Dos métodos permiten manipular el receptor
(contexto):

- fn.call(context

[, arg1 [, arg2 [...]]])

var a = [1,2,3];
Array.prototype.slice.call(a, 1, 2); // [2]

- fn.apply(context,

arglist)

var a = [1,2,3];
Array.prototype.slice.apply(a, [1, 2]); // [2]
El receptor: this
var nombre = "Objeto Global";
function saluda() {
alert("Hola! Soy " + this.nombre);
}
var alicia = {
nombre: "Alicia"
};
saluda();
saluda.call(alicia);
arguments
• El otro parámetro oculto
• Contiene una lista de todos los argumentos
• NO es un Array
function echoArgs() {
alert(arguments); // [object Arguments]
}
echoArgs(1, 2, 3, 4);
arguments
• Se comporta (más o menos) como Array...
function echoArgs() {
alert(arguments[0]); // 1
}
echoArgs(1, 2, 3, 4);

• ...pero NO del todo
function echoArgs() {
return arguments.slice(0, 1); // Error!
}
echoArgs(1, 2, 3, 4);
arguments
• Un truco:
function echoArgs() {
var slice = Array.prototype.slice;
return slice.call(arguments, 0, 1);
}
echoArgs(1, 2, 3, 4); // [1]
arguments
¡Cuidado, se comporta como parámetro oculto!
function exterior() {
var interior = function() {
alert(arguments.length);
};
interior();
}
exterior("a", "b", "c");
intermedio: this y arguments
¿Qué hace esta función?
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}

var algo = misterio();
typeof algo; // ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}

var algo = misterio();
algo(); // ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}

var algo = misterio({}, function() {
return this;
});
typeof algo(); // ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
var obj = {};
var algo = misterio(obj, function() {
return this;
});
obj === algo(); // ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
var obj = {};
var algo = misterio({}, function() {
return this;
});
obj === algo(); // ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
var obj = {
nombre: "Bárbara"
};
var algo = misterio(obj, function() {
return this.nombre;
});
algo(); /// ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
var obj = {
nombre: "Bárbara"
};
var algo = misterio(obj, function (saludo) {
return saludo + " " + this.nombre;
});
algo("Hola, "); /// ???
Intermedio: this y arguments
function misterio(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
var barbara = { nombre: "Bárbara" };
var carlos = { nombre: "Carlos" };
var algo = misterio(barbara, function (saludo) {
return saludo + " " + this.nombre;
});
algo.call(carlos, "Hola, "); /// ???
Intermedio: this y arguments
•

bind: fija una función a un contexto
function bind(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
Intermedio: this y arguments
Volviendo al problema:
var obj = {
clicks: 0,
init: function() {
$("#element").click(function() {
// MAL
this.clicks += 1;
});
}
};
obj.init();
Intermedio: this y arguments
Apaño:
var obj = {
clicks: 0,
init: function() {
var that = this;
$("#element").click(function() {
that.clicks += 1;
});
}
};
obj.init();
Intermedio: this y arguments
¿Qué pasa si el callback es un método?
var obj = {
clicks: 0,
incClicks: function() {
this.clicks += 1;
},
init: function() {
$("#element").click(
// ???
);
}
};
obj.init();
Intermedio: this y arguments
Apaño cada vez más feo:
var obj = {
clicks: 0,
incClicks: function() {
this.clicks += 1;
},
init: function() {
var that = this;
$("#element").click(function() {
that.incClicks();
});
}
};
Intermedio: this y arguments
•

bind al rescate
var obj = {
clicks: 0,
incClicks: function() {
this.clicks += 1;
},
init: function() {
$("#element").click(
bind(this, this.incClicks)
);
}
};
intermedio: this y arguments
¿Qué hace esta otra función?
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
typeof enigma(); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
var cosa = enigma();
typeof cosa(); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
var cosa = enigma(function() {
return "Hola!";
});
cosa(); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
function saluda(nombre) {
return "Hola, " + nombre + "!";
}
var cosa = enigma(saluda);
cosa("Mundo"); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
function saluda(nombre) {
return "Hola, " + nombre + "!";
}
var cosa = enigma(saluda, "Mundo");
cosa(); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
function saluda(saludo, nombre) {
return saludo + ", " + nombre + "!";
}
var cosa = enigma(saluda, "Hola", "Mundo");
cosa(); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
function saluda(saludo, nombre) {
return saludo + ", " + nombre + "!";
}
var cosa = enigma(saluda, "Hola");
cosa("Mundo"); // ???
cosa("Don Pepito"); // ???
intermedio: this y arguments
function enigma(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
var dario = {nombre: "Darío"};
var elena = {nombre: "Elena"};
function saluda(saludo) {
return saludo + ", " + this.nombre + "!";
}
var cosa = enigma(saluda, "Qué pasa");
cosa.call(dario); // ???
cosa.call(elena); // ???
Intermedio: this y arguments
•

curry: aplicación parcial de una función
function curry(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
Intermedio: rizar el rizo
var unObj = {
nombre: "Manuel",
edad: 32
};
function
function
function
function

getNombre() { return this.nombre; }
setNombre(nombre) { this.nombre = nombre; }
getEdad() { return this.edad; }
setEdad(edad) { this.edad = edad; }

var bindToUnObj = curry(bind, unObj),
getUnObjNombre = bindToUnObj(getNombre),
setUnObjNombre = bindToUnObj(setNombre);
setUnObjNombre("Pepito");
getUnObjNombre(); // ???
Intermedio: rizar el rizo
function getter(prop) { return this[prop]; }
function setter(prop, value) { this[prop] = value; }
var manuel = {
nombre: "Manuel",
edad: 32
};
var edadDeManuel = bind(manuel, curry(getter, "edad"));
edadDeManuel(); // ???
Prototipos
Prototipos
• ¿Por qué tan mala fama?
• ¡Es un mecanismo muy sencillo!
• Distinto a otros lenguajes
Prototipos
Un objeto obj:
var obj = {uno: 1, dos: 2};

qué pasa si hacemos:
obj.uno; // 1
Prototipos
obj

var obj = {uno: 1, dos: 2};

uno

1

dos

2

uno

1

dos

2

obj

obj.uno; // 1
Prototipos
obj

var obj = {uno: 1, dos: 2};

uno

1

dos

2

Si hacemos:

obj.tres; // undefined

obj
uno

1

dos

2

Not found!

undefined
Prototipos
obj

var obj = {uno: 1, dos: 2};

uno

1

dos

2

¿De dónde sale?

obj.toString(); //

'[object Object]'

obj
uno

1

dos

2

Not found!

undefined

¿?
Prototipos
obj.toString(); // '[object Object]'

obj
uno

1

dos

2

prototype

Object
Object
toString

function

valueOf

function

...
Not found!

undefined
Prototipos
Teniendo:
a

Object

b
uno

1

tres

3

toString

function

dos

2

cuatro

4

valueOf

function

prototype

b

prototype

Object

...
Not found!

undefine
d
Prototipos
a.uno; //

a

1

Object

b
uno

1

tres

3

toString

function

dos

2

cuatro

4

valueOf

function

prototype

b

prototype

Object

...
Not found!

undefine
d
Prototipos
a.cuatro; //

a

4

Object

b
uno

1

tres

3

toString

function

dos

2

cuatro

4

valueOf

function

prototype

b

prototype

Object

...
Not found!

undefine
d
Prototipos
a.toString; //

a

[object Object]

Object

b
uno

1

tres

3

toString

function

dos

2

cuatro

4

valueOf

function

prototype

b

prototype

Object

...
Not found!

undefine
d
Prototipos
a.noExiste; //

a

undefined

Object

b
uno

1

tres

3

toString

function

dos

2

cuatro

4

valueOf

function

prototype

b

prototype

Object

...
Not found!

undefine
d
Prototipos
Pero... ¿Cómo establezco el prototipo de un objeto?

- No se puede hacer directamente
- No se puede modificar el prototipo de objetos literales
- Solo objetos generados (con new)
- Constructores!
Repaso: Mensajes
• Una función se puede ejecutar de 4 maneras:
- Invocando directamente la función
(function() { alert("Hey!"); })();

- Enviando un mensaje a un objeto (método)
objeto.metodo();

- Como constructor
new MiConstructor();

- Indirectamente, a través de call(...)
fn.call({}, "param");

y

apply(...)
Repaso: Mensajes
Una función se puede ejecutar de 4 maneras:
Invocando directamente la función
Enviando un mensaje a un objeto (método)

- Como constructor
new MiConstructor();
Constructores
• Funciones
• Invocación precedida por new
• Su contexto es un objeto recién generado
• return implícito
• La única manera de manipular prototipos
Constructores
function Constructor(param) {
// this tiene otro significado!
this.propiedad = "una propiedad!";
this.cena = param;
}
var instancia = new Constructor("Pollo asado");
instancia.propiedad; // una propiedad!
instancia.cena; // "Pollo asado"
Constructores
function Constructor(param) {
// this tiene otro significado!
this.propiedad = "una propiedad!";
this.cena = param;
}
var instancia = new Constructor("Pollo asado");
instancia.propiedad; // una propiedad!
instancia.cena; // "Pollo asado"
Constructores
3 pasos:
1. Crear un nuevo objeto
2. Prototipo del objeto = propiedadad prototype del
constructor
3. El nuevo objeto es el contexto del constructor
Constructores
var b = {
uno: 1,
dos: 2
};
function A() {
this.tres = 3;
this.cuatro = 4;
}
A.prototype = b;
var instancia = new A();
instancia.tres; // 3
instancia.uno; // 1
Constructores
var b = {
uno: 1,
dos: 2
};

instancia

A.prototype = b;
var instancia = new A();
instancia.tres; // 3
instancia.uno; // 1

1

dos

2

proto

function A() {
this.tres = 3;
this.cuatro = 4;
}

uno

b

tres

3

cuatro

4

proto

Object

b
Constructores
.hasOwnProperty(name)

• Distinguir las propiedades heredadas de las propias
• true solo si la propiedad es del objeto
instancia.hasOwnProperty("tres"); // true
instancia.hasOwnProperty("uno"); // false
Constructores
¿Qué pasa aquí?
var comun = { empresa: "ACME" };
function Empleado(nombre) {
this.nombre = nombre;
}
Empleado.prototype = comun;
var pepe = new Empleado("Pepe");
pepe.nombre; // "Pepe"
pepe.empresa; // ???
Constructores
¿Qué pasa aquí?
var comun = { empresa: "ACME" };
function Empleado(nombre) {
this.nombre = nombre;
}
Empleado.prototype = comun;
var pepe = new Empleado("Pepe");
comun.empresa = "Googlezon";
var antonio = new Empleado("Antonio");
antonio.empresa; // ???
Constructores
¿Qué pasa aquí?
var comun = { empresa: "ACME" };
function Empleado(nombre) {
this.nombre = nombre;
}
Empleado.prototype = comun;
var pepe = new Empleado("Pepe");
comun.empresa = "Googlezon";
var antonio = new Empleado("Antonio");
pepe.empresa; // ???
Constructores
comun
empresa

“ACME”

proto

Object

pepe
nombre

“Pepe”

proto

comun

var pepe = new Empleado("Pepe");
Constructores
comun
empresa

“Googlezone”

proto

Object

pepe
nombre

“Pepe”

proto

comun

comun.empresa = "Googlezon";
Constructores
comun
empresa

“Googlezone”

proto

Object

pepe

antonio

nombre

“Pepe”

nombre

“Antonio”

proto

comun

proto

comun

var antonio = new Empleado("Antonio");
Constructores
comun
empresa

“Googlezone”

proto

Object

pepe

antonio

nombre

“Pepe”

nombre

“Antonio”

proto

comun

proto

comun

pepe.empresa;
Prototipos
Es decir:

• Las propiedades de los prototipos se comparten!
• Se resuelven dinámicamente
• Modificar un prototipo afecta a todas las instancias
anteriores (y futuras)!
Intermedio: constructores
¿Cómo hacer que C herede de B que hereda de A?
Intermedio: constructores
¿Cómo hacer que C herede de B que hereda de A?
C

A

B
uno

1

dos

2

tres

3

proto

B

proto

A

proto

Object

var instancia = new C();
instancia.tres; // 3
Intermedio: constructores
function C() {
this.uno = 1;
}
var instancia = new C();
instancia.tres;
Intermedio: constructores
var B = {dos: 2};
function C() {
this.uno = 1;
}
C.prototype = B;
var instancia = new C();
instancia.tres;
Intermedio: constructores
var A = {tres: 3};
function B() {
this.dos = 2;
}
B.prototype = A;
function C() {
this.uno = 1;
}
C.prototype = B;
var instancia = new C();
instancia.tres;
Intermedio: constructores
var A = {tres: 3};
function B() {
this.dos = 2;
}
B.prototype = A;
function C() {
this.uno = 1;
}
C.prototype = B;
var instancia = new C();
instancia.dos; // !!!
Intermedio: constructores
var A = {tres: 3};
function B() {
this.dos = 2;
}
B.prototype = A;
function C() {
this.uno = 1;
}
C.prototype = B;
typeof C.prototype; // ???
C.prototype.dos;
// ???
Intermedio: constructores
var A = {tres: 3};
function B() {
this.dos = 2;
}
B.prototype = A;
function C() {
this.uno = 1;
}
C.prototype = new B();
var instancia = new C();
instancia.tres;
Intermedio: constructores
function A() {
this.tres = 3;
}
function B() {
this.dos = 2;
}
B.prototype = new A();
function C() {
this.uno = 1;
}
C.prototype = new B();
var instancia = new C();
instancia.tres;
Cadena de prototipos
La herencia en varios niveles necesita:

• Encadenar prototipos
• El prototipo del “sub constructor” ha de ser siempre
new Padre()

• Es la única manera de mantener el “padre del padre” en
la cadena!
Mecanismos de herencia
Mecanismos de herencia
• Herencia clásica
• Herencia de prototipos
• Mixins (módulos)
• Extra: herencia funcional
Herencia clásica
¿Qué significa?

• Clases!
• El tipo de herencia más común en otros lenguajes
• Encapsulado y visibilidad
Herencia clásica
Vamos a empezar por un constructor:
function MiClase() {
// ???
}
var instancia = new MiClase();
Herencia clásica
Las propiedades (públicas)
function MiClase() {
this.unaPropiedad = "valor";
this.otraPropiedad = "otro valor";
}
var instancia = new MiClase();
Herencia clásica
¿Métodos?
Herencia clásica
¿Métodos?
function MiClase() {
this.unaPropiedad = "valor";
this.otraPropiedad = "otro valor";
this.unMetodo = function() {
alert(this.unaPropiedad);
};
this.otroMetodo = function() {
alert(this.otraPropiedad);
};
}
var instancia = new MiClase();
instancia.otroMetodo();
Herencia clásica
Mejor así:
function MiClase() {
this.unaPropiedad = "valor";
this.otraPropiedad = "otro valor";
}
MiClase.prototype.unMetodo = function() {
alert(this.unaPropiedad);
};
MiClase.prototype.otroMetodo = function() {
alert(this.otraPropiedad);
};
var instancia = new MiClase();
instancia.otroMetodo();
Herencia clásica
Solo falta...

function Superclase() { /* ... */ }
function MiClase() {
this.unaPropiedad = "valor";
this.otraPropiedad = "otro valor";
}
MiClase.prototype = new Superclase();
MiClase.prototype.unMetodo = function() {
alert(this.unaPropiedad);
};
MiClase.prototype.otroMetodo = function() {
alert(this.otraPropiedad);
};
Herencia clásica
¿Cómo se pueden crear métodos “de clase”?
MiClase.metodoEstatico("hola!");
Herencia clásica
¿Cómo se pueden crear métodos “de clase”?
MiClase.metodoEstatico("hola!");

¡Los constructores son objetos!
MiClase.metodoEstatico = function(cadena) {
console.log("metodoEstatico:", cadena);
}
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:

• ¡No es fácil invocar al super constructor!
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
this.raza = raza;
}
Perro.prototype = new Animal();
Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
// ???
this.raza = raza;
}
Perro.prototype = new Animal();
Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
Animal("perro");
this.raza = raza;
}
Perro.prototype = new Animal();
Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
Animal("perro");
this.raza = raza;
}
Perro.prototype = new Animal();

crea glob. especie!

Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
this = new Animal("perro");
this.raza = raza;
}
Perro.prototype = new Animal();
Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
this = new Animal("perro");
this.raza = raza;
}
Perro.prototype = new Animal();

ERROR!

Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
function Animal(especie) {
this.especie = especie;
}
Animal.prototype.getEspecie = function() {
return this.especie;
}
function Perro(raza) {
Animal.call(this, "perro");
this.raza = raza;
}
Perro.prototype = new Animal();
Perro.prototype.describir = function() {
return this.getEspecie() + ", de raza " + this.raza;
}
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:

• ¡No es fácil invocar al super constructor!
• No es fácil encapsular
Herencia clásica: Cuidado!
function MiClase() {
this.propPublica = "pública!";
}
MiClase.prototype.metPublico = function() {
return "público!";
}
var instancia = new MiClase();
instancia.propPublica; // "pública!"
instancia.metPublico();
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:

• ¡No es fácil invocar al super constructor!
• No es fácil encapsular...
• ¡Se crea una instancia solo para mantener la cadena de
prototipos!
Herencia clásica: Cuidado!
function Superclase() {
operacionMuyCostosa();
alert(“Oh, no!”);
}
function MiClase() {
// ...
}
MiClase.prototype = new Superclase();
Herencia clásica?
¿Qué se puede hacer?
Herencia clásica?
Hay dos enfoques:
Herencia clásica?
Hay dos enfoques:

• El simple
El “simple”
“Hagamos una funcioncita!”
function inherits(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
// extra
subClass.prototype.superclass = superClass;
}
El “simple”
function Animal() { }
Animal.prototype.mover = function() {
console.log("El animal se mueve...");
};
Animal.prototype.comer = function() {
console.log("¡Ñam!");
};
function Perro(raza) {
this.superclass.call(this);
}
inherits(Perro, Animal);
Perro.prototype.comer = function() {
console.log("El perro va a por su plato...");
this.superclass.prototype.comer.call(this);
};
var p = new Perro("terrier");
p.mover();
p.comer();
p instanceof Perro;
El “simple”
function Animal() { }
Animal.prototype.mover = function() {
console.log("El animal se mueve...");
};
Animal.prototype.comer = function() {
console.log("¡Ñam!");
};
function Perro(raza) {
this.superclass.call(this);
}
inherits(Perro, Animal);
Perro.prototype.comer = function() {
console.log("El perro va a por su plato...");
this.superclass.prototype.comer.call(this);
};
var p = new Perro("terrier");
p.mover();
p.comer();
p instanceof Perro;

OMG!
El “simple”
• Ventajas
- Muy simple de implementar
- Muy ligero
- No añade demasiado ruido

• Inconvenientes
- No soluciona mucho...
- No se “heredan” los métodos/propiedades de clase
- Sigue sin ser cómodo de usar
El “simple”
Caso práctico: CoffeeScript
var __hasProp = {}.hasOwnProperty,
__extends = function (child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
El “simple”
Caso práctico: CoffeeScript
var __hasProp = {}.hasOwnProperty,
__extends = function (child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
El “simple”
var MiClase = (function(_super) {
__extends(MiClase, _super);
function MiClase() {
MiClase.__super__.constructor.apply(this, arguments);
this.miPropiedad = 1;
}
MiClase.prototype.miMetodo = function() {
return MiClase.__super__.miMetodo.call(this, "hola");
};
return MiClase;
})(Superclase);
Herencia clásica?
Hay dos enfoques:

• El simple
• El cómodo
El cómodo
Más complejo, pero merece la pena
var Persona = Class.extend({
init: function(nombre) {
console.log("Bienvenido,", nombre);
}
});
var Ninja = Persona.extend({
init: function(){
this._super("ninja");
}
esgrimirEspada: function(){
console.log("En guardia!");
}
});
El cómodo
Más complejo, pero merece la pena
var Persona = Class.extend({
init: function(nombre) {
console.log("Bienvenido,", nombre);
}
});
var Ninja = Persona.extend({
init: function(){
this._super("ninja");
}
esgrimirEspada: function(){
console.log("En guardia!");
}
});
Intermedio: klass.js
¡Rellena los huecos!
var Class = function(){};
Class.extend = function(prop) {
var _super = this.prototype;
// ...
return Klass;
};
Intermedio: klass.js
Está muy bien pero...

• No hay métodos de clase (y no se heredan!)
• Todo sigue siendo público
• ¡Es solo una primera versión!
El cómodo
¿Cuándo usar este método?

• ¡Siempre que sea posible!
Contras:

• La implementación es más compleja...
• Hay que incluir la librería externa
• No es el enfoque “tradicional”
Herencia de prototipos
Vamos a cambiar de marcha...
Herencia de prototipos
Vamos a cambiar de marcha...
¡Ahora, sin clases!
Herencia de prototipos
Vamos a cambiar de marcha...
¡Ahora, sin clases!
¿¿Cómo puede haber POO sin clases??
Herencia de prototipos
Herencia clásica: categorías

-Definir “Persona”
-crear instancias de persona según la definición
-Para hacer más concreto, ¡redefine!
Herencia de prototipos
Herencia clásica: categorías

-Definir “Persona”
-crear instancias de persona según la definición
-Para hacer más concreto, ¡redefine!
Herencia de prototipos: ejemplos

-“Como ese de ahí, pero más alto”
-Cualquier objeto concreto puede servir de ejemplo
-Para hacer más concreto, ¡cambia lo que quieras!
Herencia de prototipos
var benito = {
nombre: "Benito",
edad: 36,
profesión: "jardinero",
saludar: function() {
alert("Buen día!");
},
envejecer: function() {
this.edad += 1;
}
};
Herencia de prototipos
var benito = {
nombre: "Benito",
edad: 36,
profesión: "jardinero",
saludar: function() {
alert("Buen día!");
},
envejecer: function() {
this.edad += 1;
}
};
var gonzalo = clone(benito);
gonzalo.nombre = "Gonzalo";
gonzalo.profesion = "carpintero";
gonzalo.saludar(); // Buen día!
Herencia de prototipos
var benito = {
nombre: "Benito",
edad: 36,
profesión: "jardinero",
saludar: function() {
alert("Buen día!");
},
envejecer: function() {
this.edad += 1;
}
};
var gonzalo = clone(benito);
gonzalo.nombre = "Gonzalo";
gonzalo.profesion = "carpintero";
gonzalo.saludar(); // Buen día!
Herencia de prototipos
También se puede generalizar
var Animal = {
vivo: true,
comer: function() {
console.log("Ñam, ñam");
}
};
var Perro = clone(Animal);
Perro.especie = "perro";
var Dogo = clone(Perro);
Dogo.raza = "dogo";
var toby = clone(Dogo);
toby.nombre = "Toby";
Herencia de prototipos
¡Así de simple!
function clone(obj) {
function F(){}
F.prototype = obj;
return new F();
}
Herencia de prototipos
Herencia clásica vs. de prototipos

• Clásica
✓ MUCHO más extendida y bien comprendida
✓ Mayor catálogo de mecanismos de abstracción

• Prototipos
✓ Uso mucho más eficiente de la memoria
✓ La “auténtica” herencia en JS
✓ Muy simple
Herencia de prototipos
Peeero...

• Clásica
๏ Solo se puede emular. Necesario entender los prototipos.
๏ A contrapelo

• Prototipos
๏ Bastante limitada
๏ Lenta con cadenas de prototipos largas!
Herencia de prototipos
¿Cuál uso?
Herencia de prototipos
¿Cuál uso?
¡Las dos!
Intermedio: prototipos
¿Qué significa?
objeto.propiedad;
Intermedio: prototipos
¿Qué significa?
objeto.propiedad;

“Accede a la propiedad propiedad del objeto objeto”
Intermedio: prototipos
¿Qué significa?
objeto.propiedad;

“Accede a la propiedad propiedad del objeto objeto.
Si no la encuentras, sigue buscando por la cadena
de prototipos.”
Intermedio: prototipos
¿Qué significa?
objeto.propiedad = 1;
Intermedio: prototipos
¿Qué significa?
objeto.propiedad = 1;

“Guarda el valor 1 en la propiedad propiedad del
objeto objeto.”
Intermedio: prototipos
¿Qué significa?
objeto.propiedad = 1;

“Guarda el valor 1 en la propiedad propiedad del
objeto objeto. Si no la encuentras, créala!”
Intermedio: prototipos
pluma

plomo
proto

peso

1

proto

pluma

Object

var pluma = {
peso: 1
};
var plomo = clone(pluma);
Intermedio: prototipos
pluma

plomo
proto

peso

1

proto

pluma

Object

plomo.peso; // 1
Intermedio: prototipos
pluma

plomo
proto

pluma

peso

1

peso

100

proto

Object

plomo.peso = 100;
Intermedio: prototipos
Es decir:

• Hay asimetría entre escritura y lectura!
• Lectura: busca en la cadena
• Escritura: crea una nueva propiedad
• Es el comportamiento natural
• Uso eficiente de la memoria: solo se crean los valores
diferentes.
Intermedio: prototipos
¿Qué sucede?
var Lista = {
elementos: []
};
var laCompra = clone(Lista);
laCompra.elementos.push("Leche");
laCompra.elementos.push("Huevos");
var toDo = clone(Lista);
toDo.elementos.push("Contestar emails");
toDo.elementos.push("Subir a producción");
toDo.elementos;
prototipos
Object.create(proto)

• Igual que clone
• Nativo en algunos navegadores
var pluma = {
peso: 1,
enStock: true,
};
var plomo = Object.create(pluma);
plomo.peso = 100;
¡Se acabaron los prototipos!
Clausuras
Sólo una idea importante más: ámbitos
Clausuras
• Una idea sencilla, pero difícil de explicar
• Están por todas partes
• Consecuencia natural del lenguaje
• ¡Muy útiles!
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
typeof fn;
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
fn(); // ???
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
fn();

fn = function() {
return a;
}
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
fn();

fn = function() {
return a;
}
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
fn();

fn = function() {
return a;
}
Clausuras
function clausurator() {
var a = 1;
return function() {
return a;
};
}
var fn = clausurator();
fn();

fn = function() {
return a;
}

a = 1;
Clausuras
Otro caso:
function makeContador() {
var i = 0;
return function() {
return i++;
}
}
var contador1 = makeContador();
contador1(); // ???
contador1(); // ???
var contador2 = makeContador();
contador2(); // ???
Clausuras
Otro caso:
function makeContador() {
var i = 0;
return function() {
return i++;
}
}
var contador1 = makeContador();
contador1(); // 0
contador1(); // 1
var contador2 = makeContador();
contador2(); // 0
Clausuras
function makeContador() {
var i = 0;
return function() {
return i++;
}
}
var contador1 = makeContador();
contador1(); // 0
contador1(); // 1
var contador2 = makeContador();
contador2(); // 0

contador1 = function() {
return i++;
}

i = 0;
Clausuras
function makeContador() {
var i = 0;
return function() {
return i++;
}
}
var contador1 = makeContador();
contador1(); // 0
contador1(); // 1
var contador2 = makeContador();
contador2(); // 0

contador1 = function() {
return i++;
}

i = 1;
Clausuras
function makeContador() {
var i = 0;
return function() {
return i++;
}
}
var contador1 = makeContador();
contador1(); // 0
contador1(); // 1

contador1 = function() {
return i++;
}

i = 1;

contador2 = function() {
return i++;
}

var contador2 = makeContador();
contador2(); // 0
i = 0;
Clausuras
function interesante() {
var algo = 0;
return {
get: function() {
return algo;
},
set: function(valor) {
return algo = valor;
}
};
}
var obj = interesante();
obj.get(); // ???
obj.set("hola!");
obj.get(); // ???
Clausuras
•

bind: fija una función a un contexto
function bind(ctx, fn) {
return function() {
return fn.apply(ctx, arguments);
}
}
Clausuras
•

curry: aplicación parcial de una función
function curry(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
var newargs = slice.call(arguments);
return fn.apply(this, args.concat(newargs));
};
}
Clausuras
Es decir:

• Las clausuras son función + entorno
• Asocian datos a funciones
• No se puede acceder directamente a las variables
clausuradas desde el exterior de la función

• Duración indefinida
• ¡Son muy útiles!
Intermedio: herencia funcional
function PseudoConstructor() {
var self = {};
self.propiedad = "valor";
return self;
}
var pseudoInstancia = PseudoConstructor();
pseudoInstancia.propiedad; // "valor"
Intermedio: herencia funcional
function PseudoConstructor() {
var self = {};
self.propiedad = "valor";
self.metodo = function(nombre) {
return "No te duermas, " + nombre + "!";
};
return self;
}
var pseudoInstancia = PseudoConstructor();
pseudoInstancia.metodo("Abraham");
Intermedio: herencia funcional
function PseudoConstructor() {
var self = {};
self.propiedad = "valor";
self.metodo = function(nombre) {
return "No te duermas, " + nombre + "!";
};
return self;
}
var pseudoInstancia = PseudoConstructor();
pseudoInstancia.metodo("Abraham");
Intermedio: herencia funcional
function PseudoConstructor() {
var self = {},
propiedad = "privada!";
var metodoPrivado = function(s) {
return s.toUpperCase();
}
self.metodo = function(nombre) {
var mayus = metodoPrivado(nombre);
return "No te duermas, " + mayus + "!";
};
return self;
}
var pseudoInstancia = PseudoConstructor();
pseudoInstancia.metodo("Abraham");
Intermedio: herencia funcional
1. Crear un pseudoconstructor
2. Definir una variable self con un objeto vacío
3. Añadir las propiedades/métodos públicos a self
4. Devolver self
Intermedio: herencia funcional
¿Y para heredar?
Intermedio: herencia funcional
¿Y para heredar?
function A() {
var self = {};
self.uno = 1;
return self;
}
function B() {
var self = A();
self.dos = 2;
return self;
}
var b = B();
b.uno; // 1
Intermedio: herencia funcional
¿Cómo llamar al supermétodo?
Intermedio: herencia funcional
function A() {
var self = {};
self.metodo = function() {
console.log("A");
}
return self;
}
function B() {
var self = A();
var superMetodo = self.metodo;
self.metodo = function() {
superMetodo();
console.log("B");
}
return self;
}
Intermedio: herencia funcional
“Herencia funcional”:

✓ Explotar clausuras y objetos en linea
✓ Extremadamente simple e intuitivo
✓ Mejor encapsulado público/privado
✓ Poco ruido sintáctico
✓ No hacen falta helpers ni librerías
Intermedio: herencia funcional
“Herencia funcional”:

✓ Explotar clausuras y objetos en linea
✓ Extremadamente simple e intuitivo
✓ Mejor encapsulado público/privado
✓ Poco ruido sintáctico
✓ No hacen falta helpers ni librerías
๏ Un poco... ¿cutre?
๏ No es la manera más popular
๏ ¡Peor uso de la memoria!
Programación Funcional



made with love by Redradix (www.redradix.com)
¿Programación funcional?
La vamos a entender como

• Creación y manipulación de funciones
• Alteración de funciones
• Aplicación de funciones
• Asincronía
Funciones de orden superior
Funciones que devuelven funciones

• curry
• bind
• ¡Muchas otras!
Funciones de orden superior
Algunas de las más útiles:

• throttle
• debounce
• once
• after
• compose
• memoize
throttle
Controlar la frecuencia de invocación

• La función se invocará como máximo una vez
• Durante el periodo de tiempo especificado
throttle
var counter = 0,
inc = function() { counter++; };
inc = throttle(inc, 10);
for (var i=100000; i--;) {
inc();
}
alert(counter); // ~6
throttle
function throttle(fn, time) {
var last = 0;
return function() {
var now = new Date();
if ((now - last) > time) {
last = now;
return fn.apply(this, arguments);
}
}
}
debounce
Ejecutar la función cuando se deje de llamar

• La llamada se pospone hasta que pasen x ms
• Desde la última invocación
debounce
var counter = 0,
inc = function() {
counter++;
alert(counter);
};
inc = debounce(inc, 1000);
for (var i=100000; i--;) {
inc();
}
debounce
function debounce(fn, time) {
var timerId;
return function() {
var args = arguments;
if (timerId) clearTimeout(timerId);
timerId = setTimeout(bind(this, function() {
fn.apply(this, args);
}), time);
}
}
once
La función solo se puede invocar una vez
var counter = 0,
inc = function() {
counter++;
};
inc = once(inc);
for (var i=100000; i--;) {
inc();
}
alert(counter);
once
function once(fn) {
var executed = false;
return function() {
if (!executed) {
executed = true;
return fn.apply(this, arguments);
}
}
}
after
La función se ejecuta solo tras haber sido invocada n
veces
var counter = 0,
inc = function() {
counter++;
};
inc = after(inc, 1000);
for (var i=100000; i--;) {
inc();
}
alert(counter);
after
function after(fn, n) {
var times = 0;
return function() {
times++;
if (times % n == 0) {
return fn.apply(this, arguments);
}
}
}
compose
Composición de funciones
function multiplier(x) {
return function(y) { return x*y; }
}
var randCien = compose(Math.floor,
multiplier(100),
Math.random);
alert(randCien());
compose
function compose() {
var fns = [].slice.call(arguments);
return function(x) {
var currentResult = x, fn;
for (var i=fns.length; i--;) {
fn = fns[i];
currentResult = fn(currentResult);
}
return currentResult;
}
}
memoize
Nunca calcules el mismo resultado 2 veces!

• La primera invocación calcula el resultado
• Las siguientes devuelven el resultado almacenado
• Solo vale para funciones puras
memoize
function fact(x) {
if (x == 1) { return 1; }
else { return x * fact(x-1); }
}
fact = memoize(fact);
var start = new Date();
fact(100);
console.log(new Date() - start);
start = new Date();
fact(100);
console.log(new Date() - start);
memoize
function memoize(fn) {
var cache = {};
return function(p) {
var key = JSON.stringify(p);
if (!(key in cache)) {
cache[key] = fn.apply(this, arguments);
}
return cache[key];
}
}
Asincronía
JS es, por naturaleza, asíncrono

• Eventos
• AJAX
• Carga de recursos
Asincronía
¿Qué significa asíncrono?
function asincrona() {
var random = Math.floor(Math.random() * 100);
setTimeout(function() {
return random;
}, random);
}
Asincronía
¿Cómo devuelvo el valor random desde dentro?
function asincrona() {
var random = Math.floor(Math.random() * 100);
setTimeout(function() {
return random;
}, random);
}
Asincronía
function asincrona(callback) {
var random = Math.floor(Math.random() * 1000);
setTimeout(function() {
callback(random);
}, random);
}
asincrona(function(valor) {
alert(valor);
});
Asincronía
function asincrona(callback) {
var random = Math.floor(Math.random() * 1000);
setTimeout(function() {
callback(random);
}, random);
}
asincrona(function(valor) {
alert(valor);
});
Asincronía
function asincrona(callback) {
var random = Math.floor(Math.random() * 1000);
setTimeout(function() {
callback(random);
}, random);
}
asincrona(function(valor) {
alert(valor);
});
Asincronía
Promesas

• Otra forma de escribir código asíncrono
• Más fácil de manipular
• Más fácil de combinar
Asincronía
Promesas

• Una idea muy sencilla:
- Un objeto que representa un estado futuro

• El estado futuro puede ser:
- La resolución de la promesa en un valor
- El rechazo de la promesa con un error

• Mucho, mucho más fácil de manejar que los callbacks
Promesas
function onSuccess(data) {
/* ... */
}
function onFailure(e) {
/* ... */
}
var promesa = $.get('/mydata');
promesa.then(onSuccess, onFailure);
Promesas
promise.then(onSuccess [, onFailure])

• En caso de éxito, se invoca a onSuccess con el valor
• En caso de error, se invoca a onFailure
• Devuelve, a su vez, una promesa
Promesas
¿Para qué sirven?

• Dar un aspecto más coherente al código
• Hacer más explícito el flow
• Gestionar los errores en cascada
Promesas
Parse.User.logIn("user", "pass", {
success: function(user) {
query.find({
success: function(results) {
results[0].save({ key: value }, {
success: function(result) {
// El objeto se guardó.
},
error: function(result, error) {
// Error.
}
});
},
error: function(error) {
// Error.
}
});
},
error: function(user, error) {
// Error.
}
});
Promesas
Parse.User.logIn("user", "pass").then(function(user) {
return query.find();
}).then(function(results) {
return results[0].save({ key: value });
}).then(function(result) {
// El objeto se guardó.
}, function(error) {
// Error.
});
Promesas
Parse.User.logIn("user", "pass").then(function(user) {
return query.find();
}).then(function(results) {
return results[0].save({ key: value });
}).then(function(result) {
// El objeto se guardó.
}, function(error) {
// Error.
});
Promesas
Casos: cuando onSuccess devuelve un valor
/* siendo promise una promesa... */
promise.then(function() {
return 42;
}).then(function(valor) {
return "La respuesta es " + valor;
}).then(function(mensaje) {
console.log(mensaje);
});
Promesas
Casos: cuando onSuccess devuelve un valor
/* siendo promise una promesa... */
promise.then(function() {
return 42;
}).then(function(valor) {
return "La respuesta es " + valor;
}).then(function(mensaje) {
console.log(mensaje);
});
Promesas
Casos: llamando varias a veces a .then
/* siendo promise una promesa... */
promise.then(function() {
console.log("primer onSuccess!");
});
promise.then(function() {
console.log("segundo onSuccess!");
});
Promesas
Casos: llamando varias a veces a .then
/* siendo promise una promesa... */
promise.then(function() {
console.log("primer onSuccess!");
}, function(e) {
console.log("primer onFailure...");
});
promise.then(function() {
console.log("segundo onSuccess!");
}, function(e) {
console.log("segundo onFailure...");
});
Promesas
Casos: capturar errores
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oops!");
}).then(function() {
console.log("Nunca llegamos aquí...");
}, function(e) {
console.log("Vaya por Dios!");
console.log(e);
});
Promesas
Casos: capturar errores
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oops!");
}).then(function() {
console.log("Nunca llegamos aquí...");
}, function(e) {
console.log("Vaya por Dios!");
console.log(e);
});
Promesas
Casos: cascada de errores
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oh no!");
}).then(function() {
console.log("Nunca se ejecuta.");
}).then(function() {
console.log("Esto tampoco.");
}, function(e) {
console.log("Vaya por Dios!");
console.log(e);
});
Promesas
Casos: cascada de errores
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oh no!");
}).then(function() {
console.log("Nunca se ejecuta.");
}).then(function() {
console.log("Esto tampoco.");
}, function(e) {
console.log("Vaya por Dios!");
console.log(e);
});
Promesas
Casos: errores localizados
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oh no!");
}).then(function() {
console.log("Nunca se ejecuta.");
}, function(e) {
console.log("Manejador del error");
}).then(function() {
/* ... */
}, function(e) {
/* este manejador no se ejecuta! */
});
Promesas
Casos: errores localizados
/* siendo promise una promesa... */
promise.then(function() {
throw new Error("Oh no!");
}).then(function() {
console.log("Nunca se ejecuta.");
}, function(e) {
console.log("Manejador del error");
}).then(function() {
/* ... */
}, function(e) {
/* este manejador no se ejecuta! */
});
Promesas
¿Cómo creo una promesa?
Promesas
Deferreds o diferidos

• Objetos que nos permiten crear y controlar promesas
de valores futuros

• Dos operaciones:
- resolve: resuelve la promesa como exitosa
- reject: rechaza la promesa como fracasada
Promesas
Promesa

Diferido

Representa un valor
futuro

Controla la generación
del valor

onSuccess

resolve(valor)

onFailure

reject(error)
Promesas
function enDiezSegundos() {
var diferido = new R.Deferred();
setTimeout(function() {
diferido.resolve(new Date());
}, 10*1000);
return diferido.promise();
}
var promesa = enDiezSegundos();
promesa.then(function(elFuturo) {
console.log("Ya han pasado diez segundos!");
console.log(elFuturo.getTime());
});
Promesas
Deferred#resolve([arg1, arg2, ...])

• Resuelve la promesa (ejecuta el callback onSuccess)
• Los parámetros con los que se llame a .resolve()
serán los que reciba el callback onSuccess

• Solo se debería llamar una vez
Promesas
Deferred#reject([arg1, arg2, ...])

• Rechaza la promesa (ejecuta el callback onFailure)
• Los parámetros con los que se llame a .reject() serán
los que reciba el callback onFailure

• Solo se debería llamar una vez
Promesas
Deferred#promise()

• Devuelve la promesa asociada al diferido
Promesas
Deferred#then(onSuccess, onFailure)

• Exactamente igual que hacer:

deferred.promise().then(...);
Promesas
Vamos a crear una librería de promesas

• Una implementación sencilla
• Que satisfaga la especificación Promises/A+
- http://promises-aplus.github.com/promises-spec/

• tema2/r-promise/index.html
Promesas
Por dónde empezar:

• Poder crear instancias de diferidos
• Poder poner un callback de éxito y uno de fracaso
• .then()
- Por ahora, que no devuelva nada
- Solo se puede llamar a una vez por diferido

• .resolve([arg1,

...])

y .reject([arg1,

- Invocan el callback adecuado
- Pasándole los parámetros adecuados

...])
Promesas
Siguientes pasos:

• Poder invocar a .then() varias veces
- Es decir, tener varios callbacks para cada caso en un mismo
diferido

• Que funcione el primer ejemplo del ejercicio
Lo último a abordar:

• Que las llamadas a .then() se puedan encadenar
• Es decir, que .then() devuelva a su vez una promesa
• Que funcione el segundo ejemplo
Promesas
when(pov1 [, pov2, ...])

• Dos utilidades:
- Homogeneizar promesas y valores en el código
- Combinar varias promesas/valores

• Devuelve siempre una promesa
• La promesa devuelta:
- Se resolverá si todas las promesas se resuelven.
- Los parámetros del callback son los valores devueltos por
cada una de las promesas.

- Se rechazará en caso contrario
Promesas

R.Deferred.when(1, 2, 3).then(function(a, b, c) {
console.log(a, b, c); // 1 2 3
});
Promesas
var p1 = new R.Deferred(),
p2 = new R.Deferred(),
p3 = new R.Deferred();
R.Deferred.when(p1, p2, p3).then(function(a, b, c) {
console.log(a, b, c); // 1 2 3
});
p1.resolve(1);
p2.resolve(2);
p3.resolve(3);
Promesas
/* Homogeneizar */
var promesaOValor = noSeQueDevuelve();
R.Deferred.when(promesaOValor).then(function(valor) {
console.log(valor);
});
Promesas
/* Homogeneizar */
var valor = 4,
promesa = new R.Deferred();
R.Deferred.when(valor, promesa).then(function(a, b) {
console.log(a, b); // 4, 5
});
promesa.resolve(5);
Promesas
var valor = 4,
promesa = new R.Deferred();
R.Deferred.when(valor, promesa).then(function(a, b) {
console.log(a, b);
}, function(e) {
alert("Oh, no!");
});
promesa.reject("No funciono");
Promesas
Implementa R.Deferred.when()

• tema2/when/index.html
Patrones y principios de diseño



made with love by Redradix (www.redradix.com)
Principios de diseño
• SRP: Single Responsibility Principle
- El código de una elemento ha de tener solo una razón
para cambiar.

- EL principio de diseño
- También el complementario: cada responsabilidad ha de
tener un único lugar en el código (D.R.Y.)
SRP
Es común ver cosas como esta:
$.ajax({ ... })
.success(function() {
cambioEnInterfaz();
mostrarModal();
if ($("#elemento").value() == "Ok") {
/* ... */
}
globalSeHaGuardado = true;
})
.error(function() {
// ...
});
SRP
O como esta:
var Widget = Class.extend({
onClick: function() { ... },
guardar: function() { ... },
render: function() { ... },
mostrarError: function() { ... }
});
SRP
var Widget = Model.extend({
guardar: function() { ... }
});
var WidgetView = View.extend({
render: function() { ... }
});
var WidgetController = Controller.extend({
onClick: function() { ... }
});
var ErrorAlert = ModalWindow.extend({
mostrarError: function() { ... }
});
SRP
Caso práctico: masonry.js

• https://github.com/desandro/masonry/blob/master/
jquery.masonry.js

• en el método _create (línea 102)...
SRP
!!!!//!sets!up!widget
!!!!_create!:!function(!options!)!{
!!!!!!//![...]
!!!!!!//!get!original!styles!in!case!we!re3apply!them!in!.destroy()
!!!!!!var!elemStyle!=!this.element[0].style;
!!!!!!this.originalStyle!=!{
!!!!!!!!//!get!height
!!!!!!!!height:!elemStyle.height!||!''
!!!!!!};
!!!!!!//!get!other!styles!that!will!be!overwritten
!!!!!!//![...]
3s.isFluid!=!this.options.columnWidth!&&!typeof!this.options.columnWidth!===!'function';
!!!!!!//!add!masonry!class!first!time!around
!!!!!!var!instance!=!this;
!!!!!!setTimeout(!function()!{
!!!!!!!!instance.element.addClass('masonry');
!!!!!!},!0!);
!!!!!!
!!!!!!//!bind!resize!method
!!!!!!if!(!this.options.isResizable!)!{
!!!!!!!!$(window).bind(!'smartresize.masonry',!function()!{!
!!!!!!!!!!instance.resize();
!!!!!!!!});
!!!!!!}
SRP
!!!!//!sets!up!widget
!!!!_create!:!function(!options!)!{
!!!!!!//![...]
!!!!!!//!get!original!styles!in!case!we!re3apply!them!in!.destroy()
!!!!!!var!elemStyle!=!this.element[0].style;
!!!!!!this.originalStyle!=!{
!!!!!!!!//!get!height
!!!!!!!!height:!elemStyle.height!||!''
!!!!!!};
!!!!!!//!get!other!styles!that!will!be!overwritten
!!!!!!//![...]
3s.isFluid!=!this.options.columnWidth!&&!typeof!this.options.columnWidth!===!'function';
!!!!!!//!add!masonry!class!first!time!around
!!!!!!var!instance!=!this;
!!!!!!setTimeout(!function()!{
!!!!!!!!instance.element.addClass('masonry');
!!!!!!},!0!);
!!!!!!
!!!!!!//!bind!resize!method
!!!!!!if!(!this.options.isResizable!)!{
!!!!!!!!$(window).bind(!'smartresize.masonry',!function()!{!
!!!!!!!!!!instance.resize();
!!!!!!!!});
!!!!!!}
SRP
El resultado: caos!

• No hay un lugar claro para cada operación
• Es difícil entender qué hace cada línea
- El “qué” está enterrado en el “cómo”

• Muy complicado de testear
• Difícil de reutilizar
SRP
Caso práctico: BrowserQuest

• https://github.com/mozilla/BrowserQuest/blob/
master/client/js/chest.js
SRP
!!!!var!Chest!=!Entity.extend({
!!!!!!!!init:!function(id,!kind)!{
!!!!!
!!!!this._super(id,!Types.Entities.CHEST);
!!!!!!!!},
!!!!
!!!!!!!!getSpriteName:!function()!{
!!!!!!!!!!!!return!"chest";
!!!!!!!!},
!!!!
!!!!!!!!isMoving:!function()!{
!!!!!!!!!!!!return!false;
!!!!!!!!},
!!!!
!!!!!!!!open:!function()!{
!!!!!!!!!!!!if(this.open_callback)!{
!!!!!!!!!!!!!!!!this.open_callback();
!!!!!!!!!!!!}
!!!!!!!!},
!!!!
!!!!!!!!onOpen:!function(callback)!{
!!!!!!!!!!!!this.open_callback!=!callback;
!!!!!!!!}
!!!!});
SRP
Caso práctico: BrowserQuest

• Todo el proyecto está muy bien estructurado
- entity.js
- character.js
- animation.js
- ...

• A pesar de ser muy grande, cada responsabilidad tiene
su sitio
SRP
Caso práctico: Backbone.js

• https://github.com/documentcloud/backbone/blob/
master/backbone.js

• en Backbone.Model, línea 179...
SRP
• Por un lado..
๏ gestión de estado (set, get)
๏ validación
๏ formateo (toJSON, escape)
๏ servidor (fetch, save)

• Por otro...
✓ Delega los detalles a otros módulos (Sync, Event)
✓ Bajo acoplamiento (“interfaces”)
SRP
“Una responsabilidad”...

• Subjetivo
• “Una sola razón para cambiar”...
- “Para qué todo funcione bien”
- Muy dependiente del nivel de abstracción
- Y de cada módulo

• El exceso es tan malo como el defecto
Principios de diseño
• Tell, Don’t Ask
- “Dime lo que necesitas”
- Claridad y expresividad
- Encapsular las comprobaciones
Tell, Don’t Ask
Los síntomas:

!!!!!!!!!!!!!if!(typeof(variables)!===!'object'!&&!!Array.isArray(variables))!{
!!!!!!!!!!!!!!!!!variables!=!Object.keys(variables).map(function!(k)!{
!!!!!!!!!!!!!!!!!!!!!var!value!=!variables[k];

!!!!!!!!!!!!!!!!!!!!!if!(!!(value!instanceof!tree.Value))!{
!!!!!!!!!!!!!!!!!!!!!!!!!if!(!!(value!instanceof!tree.Expression))!{
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!value!=!new(tree.Expression)([value]);
!!!!!!!!!!!!!!!!!!!!!!!!!}
!!!!!!!!!!!!!!!!!!!!!!!!!value!=!new(tree.Value)([value]);
!!!!!!!!!!!!!!!!!!!!!}
!!!!!!!!!!!!!!!!!!!!!return!new(tree.Rule)('@'!+!k,!value,!false,!0);
!!!!!!!!!!!!!!!!!});
!!!!!!!!!!!!!!!!!frames!=![new(tree.Ruleset)(null,!variables)];
!!!!!!!!!!!!!}
Tell, Don’t Ask
Los síntomas:

!!!!!!!!!!!!!if!(typeof(variables)!===!'object'!&&!!Array.isArray(variables))!{
!!!!!!!!!!!!!!!!!variables!=!Object.keys(variables).map(function!(k)!{
!!!!!!!!!!!!!!!!!!!!!var!value!=!variables[k];

!!!!!!!!!!!!!!!!!!!!!if!(!!(value!instanceof!tree.Value))!{
!!!!!!!!!!!!!!!!!!!!!!!!!if!(!!(value!instanceof!tree.Expression))!{
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!value!=!new(tree.Expression)([value]);
!!!!!!!!!!!!!!!!!!!!!!!!!}
!!!!!!!!!!!!!!!!!!!!!!!!!value!=!new(tree.Value)([value]);
!!!!!!!!!!!!!!!!!!!!!}
!!!!!!!!!!!!!!!!!!!!!return!new(tree.Rule)('@'!+!k,!value,!false,!0);
!!!!!!!!!!!!!!!!!});
!!!!!!!!!!!!!!!!!frames!=![new(tree.Ruleset)(null,!variables)];
!!!!!!!!!!!!!}
Tell, Don’t Ask
Programación:

• Estructurada: adquiere info y toma decisiones
• OO: manda a los objetos hacer cosas
Tell, Don’t Ask
El error:
1. Preguntar a un objeto sobre su estado
2. Tomar una decisión
3. Decirle lo que tiene que hacer
Tell, Don’t Ask
El error:
1. Preguntar a un objeto sobre su estado
2. Tomar una decisión
3. Decirle lo que tiene que hacer

¡Probablemente ese código pertenece al objeto!
Tell, Don’t Ask
if (usuario.primerLogin) {
usuario.mostrarMensajeBienvenida();
} else {
usuario.mostrarSaludo();
}
Tell, Don’t Ask
var Usuario = Class.extend({
saludar: function() {
if (this.primerLogin) {
this.mostrarMensajeBienvenida();
} else {
this.mostrarSaludo();
}
}
});
// y después...
usuario.saludar();
Tell, Don’t Ask
function comprobarTimeout(respuesta) {
if ((Date.now() - respuesta.start) > 10000) {
respuesta.notificarTimeout();
}
}
Tell, Don’t Ask
var Respuesta = Class.extend({
comprobarTimeout: function() {
if ((Date.now() - this.start) > 10000) {
this.notificarTimeout();
}
}
});
// y después...
respuesta.comprobarTimeout();
Tell, Don’t Ask
var elementos = miColeccion.getItems();
for (var i=0; i<elementos.length; i++) {
var elemento = elementos[i];
console.log(elemento.nombre);
}
Tell, Don’t Ask
miColeccion.forEach(function(e) {
console.log(e.nombre);
});
Tell, Don’t Ask
var elemento = new Elemento("hola", 12);
var lista = miColeccion.getItems();
lista.addElementAt(elemento.getOrder(), elemento);
Tell, Don’t Ask
var elemento = new Elemento("hola", 12);
miColeccion.add(elemento);
Tell, Don’t Ask
Es decir:

• Los datos y las operaciones sobre esos datos deben
estar en el mismo sitio (objeto)

• Encapsular, desacoplar
• “Command/Query Separation”
- Consulta información
- Da una orden y deja al objeto decidir
- Pero no las mezcles!
Tell, Don’t Ask
Ventajas:

✓ Más robusto (menor acoplamiento)
✓ Menor tendencia a repetir lógica
✓ Mejor estructurado
Inconvenientes:

๏ Miles de métodos de 2 o 3 líneas
๏ “Ruido” en las clases
Principios de diseño
• S.O.L.I.D.
- Single Responsibility
- Open-Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
S.O.L.I.D.
Open-Closed

• “Un elemento ha de estar abierto a la extensión pero
cerrado a la modificación”

- Abierto a la extensión: poder ser adaptado a las (futuras)
necesidades de la aplicación

- Cerrado a la modificación: que la adaptación no implique
modificar su código
Open-Closed
var Lenguas = { Castellano: 0,
Ingles: 1 };
var Persona = Class.extend({
init: function(lengua) { this.lengua = lengua; },
saludar: function(lengua) {
if (this.lengua == Lenguas.Castellano) {
alert("Hola!");
} else if (this.lengua == Lenguas.Ingles) {
alert("Hello!");
}
}
});
new Persona(Lenguas.Castellano).saludar();
Open-Closed
var Persona = Class.extend({
saludar: function() {
alert(this.saludo);
}
});
var Angloparlante = Persona.extend({
init: function() { this.saludo = "Hello!"; }
});
var Hispanohablante = Persona.extend({
init: function() { this.saludo = "Hola!"; }
});
new Hispanohablante().saludar();
Open-Closed
Pretende:

• Promover el uso de abstracciones
• Código modular y flexible ante el cambio
• Evitar un torrente de cambios en cascada!
Open-Closed
Pretende:

• Promover el uso de abstracciones
• Código modular y flexible ante el cambio
• Evitar un torrente de cambios en cascada!
Es decir:

• Especificar y respetar interfaces
Open-Closed
var Canvas = Class.extend({
render: function(figura) {
if (figura instanceof Triangulo) {
// ...
} else if (figura instanceof Cuadrado) {
// ...
}
}
});
Open-Closed
var Canvas = Class.extend({
render: function(figura) {
figura.draw(this);
}
});
var Triangulo = Figura.extend({
draw: function(canvas) { ...}
});
var Cuadrado = Figura.extend({
draw: function(canvas) { ...}
});
Open-Closed
Caso práctico: three.js

• https://github.com/mrdoob/three.js/blob/master/src/
renderers/CanvasRenderer.js

• método render, línea 225
Open-Closed
if!(!element!instanceof!THREE.RenderableParticle!)!{
//!...
}!else!if!(!element!instanceof!THREE.RenderableLine!)!{
//!...
}!else!if!(!element!instanceof!THREE.RenderableFace3!)!{
//!...
}!else!if!(!element!instanceof!THREE.RenderableFace4!)!{
//!...
}
Open-Closed
Caso práctico: jasmine.js

•https://github.com/pivotal/jasmine/blob/master/src/
core/Reporter.js
Open-Closed
/**!No3op!base!class!for!Jasmine!reporters.
!*
!*!@constructor
!*/
jasmine.Reporter!=!function()!{
};
//noinspection!JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerStarting!=!function(runner)!{
};
//noinspection!JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerResults!=!function(runner)!{
};
//...
S.O.L.I.D.
Sustitución de Liskov

• “Un objeto debe ser substituible por instancias de sus
subclases”

- Si B es subclase de A
- Y b es una instancia de B
- Se debería poder usar b allí donde se espere un objeto de
clase A
Sustitución de Liskov
var Animal = Class.extend({
caminar: function() { /*...*/ },
comer: function() { /* .. */ }
});
Sustitución de Liskov
var Animal = Class.extend({
caminar: function() { /*...*/ },
comer: function() { /* ... */ }
});
var Serpiente = Animal.extend({
/* ... */
});
var s = new Serpiente();
s.caminar();
Sustitución de Liskov
Pretende:

• Promover la reutilización segura de código
• Mantener una semántica coherente
• Si “B es un A”, entonces “B ha de comportarse como A”
S.O.L.I.D.
Segregación de la Intefaz

• “muchas interfaces cliente específicas son mejores que
una interfaz de propósito general”

- No obligues a un cliente a depender de interfaces que no
necesita

- Polución de interfaz
Segregación de la intefaz
var Modal = Class.extend({
show: function() { ... },
hide: function() { ... }
});
Segregación de la intefaz
var Modal = Class.extend({
show: function() { ... },
hide: function() { ... }
});
var Timer = Class.extend({
setTimer: function(time) { ... },
startTimer: function() { ... },
onTimeout: function() { ... }
});
Segregación de la intefaz
var Modal = Class.extend({
show: function() { ... },
hide: function() { ... }
});
var Timer = Class.extend({
setTimer: function(time) { ... },
startTimer: function() { ... },
onTimeout: function() { ... }
});
var TimedModal = Modal.extend({
init: function() {
this.setTimer(100);
this.onTimeout = this.hide;
this.show();
this.startTimer();
}
});
Segregación de la intefaz
var Timer = Class.extend({
setTimer: function(time) { ... },
startTimer: function() { ... },
onTimeout: function() { ... }
});
var Modal = Timer.extend({
show: function() { ... },
hide: function() { ... }
});
var TimedModal = Modal.extend({
init: function() {
this.setTimer(100);
this.onTimeout = this.hide;
this.show();
this.startTimer();
}
});
Segregación de la intefaz
var WidgetView = Class.extend({
init: function(cont) {
var cbind = curry(bind, cont);
$("#E1").click(cbind(cont.onE1Click));
}
});
Segregación de la intefaz
var WidgetView = Class.extend({
init: function(cont) {
var cbind = curry(bind, cont);
$("#E1").click(cbind(cont.onE1Click));
$("#E2").click(cbind(cont.onE2Click));
$("#E3").click(cbind(cont.onE3Click));
$("#E4").click(cbind(cont.onE4Click));
}
});
Segregación de la intefaz
var WidgetView = Class.extend({
init: function(cont) {
var cbind = curry(bind, cont);
$("#E1").click(cbind(cont.onE1Click));
$("#E2").click(cbind(cont.onE2Click));
$("#E3").click(cbind(cont.onE3Click));
$("#E4").click(cbind(cont.onE4Click));
$("#save").click(cbind(cont.save));
$("#reset").click(cbind(cont.reset));
$("#validate").click(cbind(cont.validate));
$("#next-page").click(cbind(cont.getNextPage));
// ...
}
});
Segregación de la intefaz
var WidgetView = Class.extend({
init: function(viewCont, cont, pagCont) {
var vbind = curry(bind, cont),
cbind = curry(bind, cont),
pbind = curry(bind, pagCont);
$("#E1").click(vbind(viewCont.onE1Click));
$("#E2").click(vbind(viewCont.onE2Click));
$("#E3").click(vbind(viewCont.onE3Click));
$("#E4").click(vbind(viewCont.onE4Click));
$("#save").click(cbind(cont.save));
$("#reset").click(cbind(cont.reset));
$("#validate").click(cbind(cont.validate));
$("#next-page").click(pbind(pagCont.getNextPage));
// ...
}
});
Segregación de la intefaz
var WidgetView = Class.extend({
init: function(viewCont, cont, pagCont) {
var vbind = curry(bind, cont),
cbind = curry(bind, cont),
pbind = curry(bind, pagCont);
$("#E1").click(vbind(viewCont.onE1Click));
$("#E2").click(vbind(viewCont.onE2Click));
$("#E3").click(vbind(viewCont.onE3Click));
$("#E4").click(vbind(viewCont.onE4Click));
$("#save").click(cbind(cont.save));
$("#reset").click(cbind(cont.reset));
$("#validate").click(cbind(cont.validate));
$("#next-page").click(pbind(pagCont.getNextPage));
// ...
}
});
S.O.L.I.D.
Dependency inversion

• “Depende de abstracciones. No dependas de
cocreciones”

- Entidades de alto nivel no deben depender de entidades de
bajo nivel. Ambos deben depender de abstracciones.

- Las abstracciones no deben depender de detalles. Los detalles
deben depender de abstracciones.
Dependency Inversion
var Model = Class.extend({
save: function() {
var tbind = curry(bind, this),
stop = bind(this.icon, this.icon.stop);
$.post(this.url, this.getData())
.success(tbind(this.saved))
.error(tbind(this.saveFailed))
.complete(stop);
}
});
Dependency Inversion
var Model = Class.extend({
save: function() {
var tbind = curry(bind, this),
stop = bind(this.icon, this.icon.stop);
$.post(this.url, this.getData())
.success(tbind(this.saved))
.error(tbind(this.saveFailed))
.complete(stop);
}
});
Dependency Inversion
var Model = Class.extend({
init: function(store) { this.store = store; }
save: function() {
var tbind = curry(bind, this),
stop = bind(this.icon, this.icon.stop);
this.store.save(
this.data,
tbind(this.saved),
tbind(this.saveFailed),
stop
);
}
});
var Store = Class.extend({
save: function(data, success, error, complete) {
});

}
Dependency Inversion
var ServerStore = Store.extend({
save: function(data, success, error, complete) {
$.post(this.url, data)
.success(success)
.error(error)
.complete(complete);
}
});
var db = {};
var MemStore = Store.extend({
save: function(data, success, error, complete) {
db[this.url] = data;
complete();
success();
}
});
Dependency Inversion
Caso práctico: backbone.js

• https://github.com/documentcloud/backbone/blob/
master/backbone.js

• Backbone.Model#fetch, línea 335
Dependency Inversion
!!!!fetch:!function(options)!{
!!!!!!options!=!options!?!_.clone(options)!:!{};
!!!!!!var!model!=!this;
!!!!!!var!success!=!options.success;
!!!!!!options.success!=!function(resp,!status,!xhr)!{
!!!!!!!!if!(!model.set(model.parse(resp,!xhr),!options))
!!!!!!!!!!return!false;
!!!!!!!!if!(success)!success(model,!resp,!options);
!!!!!!};
!!!!!!return!this.sync('read',!this,!options);
!!!!},
Patrones de organización
Patrones de organización
• Parámetros con nombre/por defecto
• Módulos y namespaces
• Control de acceso
• Mixins
Parámetros con nombre
function ajax(url, data, method,
success, error, complete) {
url || url = "/";
data || data = {};
method || method = "POST";
// ...
}
ajax("/",
{},
"GET",
function(){ ... },
function() { ... },
function() { ... });
Parámetros con nombre
function ajax(options) {
var url = options.url || "/",
data = options.data || {},
method = options.method || "POST";
//...
}
ajax({data: [1, 2], complete: function() { ... }});
Parámetros por defecto
function ajax(options) {
var fn = function() {},
defaults = {url: "/", data: [], method: "POST",
success: fn, error: fn, complete: fn};
options = merge(defaults, options);
// ...
}
ajax({data: [1, 2], complete: function() { ... }});
Parámetros por defecto
backbone.js:749
!!!!reset:!function(models,!options)!{
!!!!!!for!(var!i!=!0,!l!=!this.models.length;!i!<!l;!i++)!{
!!!!!!!!this._removeReference(this.models[i]);
!!!!!!}
!!!!!!this._reset();
!!!!!!if!(models)!this.add(models,!_.extend({silent:!true},!options));
!!!!!!if!(!options!||!!options.silent)!this.trigger('reset',!this,!options);
!!!!!!return!this;
!!!!},
Intermedio: merge
¿Cómo sería esa función merge?
Intermedio: merge
¿Cómo sería esa función merge?
function merge() {
var slice = Array.prototype.slice,
sources = slice.call(arguments),
target = {};
sources.forEach(function(source) {
for (var p in source) if (source.hasOwnProperty(p)) {
target[p] = source[p];
}
});
return target;
}
Módulos y namespaces
• JavaScript no tiene concepto de namespace
• Todo tirado en objeto global
- Mucha polución
- Colisión de nombres
- Difícil de navegar
Módulos y namespaces
• JavaScript no tiene concepto de namespace
• Todo tirado en objeto global
- Mucha polución
- Colisión de nombres
- Difícil de navegar

•¡Pero tenemos funciones!
Módulos y namespaces
function miHelper() {
// ...
}
var miVariableTemporal = 0;
var estadoLocal = {};
Módulos y namespaces
function sandbox() {
function miHelper() {
// ...
}
var miVariableTemporal = 0;
var estadoLocal = {};
}
Módulos y namespaces
(function sandbox() {
function miHelper() {
// ...
}
var miVariableTemporal = 0;
var estadoLocal = {};
}())
Módulos y namespaces
(function sandbox() {
function miHelper() {
// ...
}
var miVariableTemporal = 0;
var estadoLocal = {};
}())
Módulos y namespaces
function miFuncionUtil() {
// ...
}
function miGranMetodo() {
// ...
}
function miEstupendoHelper() {
// ...
}
Módulos y namespaces
function aux() { }
var state = "off";
function miFuncionUtil() {
// ...
}
function miGranMetodo() {
// ...
}
function miEstupendoHelper() {
// ...
}
Módulos y namespaces
(function() {
function aux() { }
var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { }
function miEstupendoHelper() { }
}())
Módulos y namespaces
var Modulo = (function() {
function aux() { }
var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { }
return {
miFuncionUtil: miFuncionUtil,
miGranMetodo: miGranMetodo
};
}());
Módulos y namespaces
var Modulo = (function() {
function aux() { }
var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { }
return {
miFuncionUtil: miFuncionUtil,
miGranMetodo: miGranMetodo
};
}());
Módulos y namespaces
Modulo.miFuncionUtil();
Módulos y namespaces
var Modulo = {};
(function(Modulo) {
function aux() { }
var state = "off";
Modulo.miFuncionUtil = function() { }
Modulo.miGranMetodo = function() { }
}(Modulo));
Módulos y namespaces
var Modulo = {};
(function(Modulo) {
function aux() { }
var state = "off";
Modulo.miFuncionUtil = function() { }
}(Modulo));
(function(Modulo) {
Modulo.miGranMetodo = function() { }
}(Modulo));
Módulos y namespaces
var Modulo = (function(Modulo) {
function aux() { }
var state = "off";
Modulo.miFuncionUtil = function() { }
return Modulo;
}(Modulo || {}));
var Modulo = (function(Modulo) {
Modulo.miGranMetodo = function() { }
return Modulo;
}(Modulo || {}));
Módulos y namespaces
var Modulo = (function(Modulo) {
function aux() { }
var state = "off";
Modulo.miFuncionUtil = function() { }
return Modulo;
}(Modulo || {}));
var Modulo = (function(Modulo) {
Modulo.miGranMetodo = function() { }
return Modulo;
}(Modulo || {}));
Módulos y namespaces
Una truco más sofisticado:

• Tenemos un módulo
• Al que añadimos propiedades en varios ficheros
• Queremos compartir cierta información entre ficheros
• Pero que no sea accesible una vez terminada la carga
Módulos y namespaces
var Modulo = (function(Modulo) {
_private.password = "1234";
}(Modulo || {}));
var Modulo = (function(Modulo) {
Modulo.login = function(pass) {
return pass == _private.password;
};
}(Modulo || {}));
Modulo._private; // undefined
Módulos y namespaces
var Modulo = (function (Modulo) {
var _private = Modulo._private = (Modulo._private || {}),
_seal = Modulo._seal = (Modulo._seal || function () {
delete Modulo._private;
delete Modulo._seal;
});
// acceso permanente a _private y _seal
return Modulo;
}(Modulo || {}));
Módulos y namespaces
var Modulo = (function (Modulo) {
var _private = Modulo._private;
// acceso a _private
}(Modulo || {}));
Módulos y namespaces
Modulo._seal();
Intermedio: mejorar klass.js
Convierte klass.js en un módulo Class
Módulos y namespaces
Submódulos: muy fácil!
var MiLibreria = {};
MiLibreria.eventos = (function(eventos) {
eventos.on = function() { };
eventos.off = function() { };
return eventos;
}(MiLibreria.eventos));
Módulos y namespaces
Según crece la aplicación...
Módulos y namespaces
Según crece la aplicación...
var MiLibreria = MiLibreria || {};
Módulos y namespaces
Según crece la aplicación...
var MiLibreria = MiLibreria || {};
MiLibreria.widgets = MiLibreria.widgets || {};
Módulos y namespaces
Según crece la aplicación...
var MiLibreria = MiLibreria || {};
MiLibreria.widgets = MiLibreria.widgets || {};
MiLibreria.widgets.buttons = MiLibreria.widgets.buttons || {};
MiLibreria.widgets.buttons.actionButtons = (function(buttons) {
buttons.ok = new Widget({ ... });
buttons.cancel = new Widget({ ... });
}(MiLibreria.widgets.buttons.actionButtons || {}));
Módulos y namespaces
Namespaces, pero más cómodos:
MiLib.namespace('widgets.buttons.actionButtons', function(my) {
my.ok = new Widget({ ... });
my.cancel = new Widget({ ... });
});
Intermedio: namespace
¿Como sería la función MiLib.namespace?
Intermedio: namespace
¿Como sería la función MiLib.namespace?
var MiLib = (function(my) {
my.namespace = function(string, sandbox) {
// ???
};
return my;
}(MiLib || {}));
Intermedio: namespace
¿Como sería la función MiLib.namespace?
var MiLib = (function(my) {
my.namespace = function(string, sandbox) {
var spaces = string.split('.'),
root = my,
space;
while (space = spaces.shift()) {
root = root[space] || (root[space] = {});
}
return sandbox(root);
};
return my;
}(MiLib || {}));
Mixins
• Otra forma de reutilizar código
• Sin las limitaciones de la herencia
• Para código de propósito general
• Algo similar a herencia múltiple
Mixins
var Mixin = function() {};
Mixin.prototype = {
inspect: function() {
var output = [];
for(key in this) {
output.push(key + ': ' + this[key]);
}
return output.join(', ');
}
};
Mixins
var Persona = Class.extend({
init: function(nombre) {
this.nombre = nombre;
}
});
augment(Persona, Mixin);
var pepito = new Persona("Pepito");
pepito.inspect();
Mixins
function augment(target, source) {
for (var prop in source.prototype) {
if(!target.prototype[prop]) {
target.prototype[prop] = source.prototype[prop];
}
}
}
Intermedio: Mejores Mixins
Lo podemos hacer mejor!

• Mejor integración con klass.js
• Callbacks de inclusión (estilo ruby)
Intermedio: Mejores Mixins
var StaticModule = {
propiedadDeClase: "Soy una propiedad de clase",
included: function(klass) { console.log("Includido!"); }
};
var InstanceModule = {
diHola: function() { alert("HOLA!"); },
mixed: function(klass) { console.log("Mezclado!"); }
};
var MiClase = Class.extend({
init: function() { }
});
MiClase.include(StaticModule);
MiClase.mixin(InstanceModule);
Patrones de creación de objetos
Factoría
Delegar la creación de un objeto

• Elegir el constructor dinámicamente
• Procesos de construcción complejos
• Desacoplar detalles de implementación
Factoría
var locales = {
es: {header: {title: "Mi Título"}},
en: {header: {title: "My Title"}}
};
var I18n = Class.extend({
translate: function(path) {
var position = locales[this.locale],
path = path.split('.'),
currentPath;
while (currentPath = path.shift()) {
position = position[currentPath];
}
return position;
}
});
var english = new I18n();
english.locale = "en";
english.translate('header.title'); // “My
Factoría
var GlobalConfig = {locale: "es"};
Factoría
var GlobalConfig = {locale: "es"};
I18n.withCurrentLocale = function() {
var instance = new this;
instance.locale = GlobalConfig.locale;
return instance;
};
Factoría
var i18n = I18n.withCurrentLocale();
alert(i18n.translate('header.title'));
Factoría
var Events = Class.extend({
on: function(event, cb) { },
off: function(event, cb) { }
});
var IEEvents = Events.extend({
on: function(event, cb) { },
off: function(event, cb) { }
});
Events.getInstance = function() {
if (checkForIExplorer()) {
return new IEEvents();
} else {
return new Events();
}
};
Factoría
Controlar las instancias
var Enemigo = (function() {
var enemigos = [];
var Enemigo = Class.extend({ /*...*/ });
Enemigo.crear = function() {
var instance;
if (enemigos.length < 5) {
instance = new Enemigo();
enemigos.push(instance);
return instance;
} else {
throw new Error("No puede haber más!");
}
}
return Enemigo;
}());
Factoría
var Recurso = (function() {
var libres = [];
var Recurso = Class.extend({
liberar: function() { libres.push(this); }
});
Recurso.crear = function() {
if (libres.length > 0) {
return libres.pop();
} else {
return new Recurso();
}
}
return Recurso;
}());
Factoría
¿Cuándo usar factorías?

• La construcción de un objeto es compleja
• Seleccionar el constructor adecuado según entorno
• Necesitamos controlar el instanciado
Singleton
Clase con una única instancia

• Un tipo peculiar de Factoría
• Cuando no tiene sentido más de una instancia
Intermedio: I18n.js
Librería de internacionalización
var Config = {locale: 'en'};
I18n.addTranslation('en', {header: {title: "My Title"}});
I18n.addTranslation('es', {header: {title: "Mi Título"}});
var i18n = I18n.withCurrentLocale();
alert(i18n.translate('header.title'));
// Singleton!
console.log(i18n === I18n.withCurrentLocale())
Patrones de abstracción
Patrones de abstracción
• Iteradores
• Decorador
• Fachada
• Estrategia
• Inyección de dependencias
• Proxy
Iteradores
Recorrer una colección

• Sin revelar detalles de implementación
• Mayor control sobre la iteración
Iteradores
var ListadoAlumnos = Class.extend({
init: function() { this.alumnos = []; },
add: function(nombre, ciudad) {
this.alumnos.push({
nombre: nombre,
ciudad: ciudad
});
}
});
Iteradores
var ListadoAlumnos = Class.extend({
init: function() { this.alumnos = []; },
add: function(nombre, ciudad) {
this.alumnos.push({
nombre: nombre,
ciudad: ciudad
});
}
});
var lista = new ListadoAlumnos();
lista.add("Gonzalo", "Madrid");
lista.add("Gerardo", "Madrid");
lista.add("Guzman", "Valencia");
Iteradores
var lista = new ListadoAlumnos();
lista.add("Gonzalo", "Madrid");
lista.add("Gerardo", "Madrid");
lista.add("Guzman", "Valencia");
var alumnos = lista.alumnos;
for (var i=0; i<alumnos.length; i++) {
if (alumnos[i].ciudad == "Madrid") {
console.log(alumnos[i].nombre);
}
}
Iteradores
var lista = new ListadoAlumnos();
lista.add("Gonzalo", "Madrid");
lista.add("Gerardo", "Madrid");
lista.add("Guzman", "Valencia");
var alumnos = lista.alumnos;
for (var i=0; i<alumnos.length; i++) {
if (alumnos[i].ciudad == "Madrid") {
console.log(alumnos[i].nombre);
}
}
Iteradores
var ListadoAlumnos = Class.extend({
init: function() { this.alumnos = []; },
add: function(nombre, ciudad) {
this.alumnos.push({ nombre: nombre, ciudad: ciudad });
},
forEachIn: function(ciudad, fn) {
for (var i=0; i<this.alumnos.length; i++)
if (this.alumnos[i].ciudad == ciudad) {
fn(this.alumnos[i].nombre);
}
}
});
Iteradores
var lista = new ListadoAlumnos();
lista.add("Gonzalo", "Madrid");
lista.add("Gerardo", "Madrid");
lista.add("Guzman", "Valencia");
lista.forEachIn("Madrid", function(n) {
console.log(n);
});
Iteradores
var ListadoAlumnos = Class.extend({
init: function() { this.alumnos = []; },
add: function(nombre, ciudad) {
this.alumnos.push({ nombre: nombre, ciudad: ciudad });
},
next: function() {
this.index = this.index || 0;
return this.alumnos[this.index++];
}
});
Iteradores
var lista = new ListadoAlumnos();
lista.add("Gonzalo", "Madrid");
lista.add("Gerardo", "Madrid");
lista.add("Guzman", "Valencia");
var alumno;
while(alumno = lista.next()) {
alert(alumno.nombre);
}
Iteradores
var Iterator = Class.extend({
init: function(collection) {
this.col = collection;
this.pos = 0;
},
next: function() {
return this.col[this.pos++];
}
});
var ListadoAlumnos = Class.extend({
init: function() { this.alumnos = []; },
add: function(nombre, ciudad) {
this.alumnos.push({ nombre: nombre, ciudad: ciudad });
},
getIterator: function() {
return new Iterator(this.alumnos);
}
});
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales
Curso Javascript profesionales

More Related Content

What's hot (15)

Backend (sf2Vigo)
Backend (sf2Vigo)Backend (sf2Vigo)
Backend (sf2Vigo)
 
Ajax
AjaxAjax
Ajax
 
Herencia y polimorfismo
Herencia y polimorfismoHerencia y polimorfismo
Herencia y polimorfismo
 
As3 unidad 2 eventos y funciones
As3 unidad 2 eventos y funcionesAs3 unidad 2 eventos y funciones
As3 unidad 2 eventos y funciones
 
Por pagar
Por pagarPor pagar
Por pagar
 
Awt
AwtAwt
Awt
 
C# calculadora
C# calculadoraC# calculadora
C# calculadora
 
Ejercicios en Netbeans
Ejercicios en NetbeansEjercicios en Netbeans
Ejercicios en Netbeans
 
11funciones 1231096290787715-2
11funciones 1231096290787715-211funciones 1231096290787715-2
11funciones 1231096290787715-2
 
jQuery 1.3 Eghost Julio2009
jQuery 1.3 Eghost Julio2009jQuery 1.3 Eghost Julio2009
jQuery 1.3 Eghost Julio2009
 
Ruby en 20 minutos
Ruby en 20 minutosRuby en 20 minutos
Ruby en 20 minutos
 
Introducción a Javascript
Introducción a JavascriptIntroducción a Javascript
Introducción a Javascript
 
Arreglos en C++
Arreglos en C++Arreglos en C++
Arreglos en C++
 
11 Funciones
11 Funciones11 Funciones
11 Funciones
 
Doc tutorial-c++
Doc tutorial-c++Doc tutorial-c++
Doc tutorial-c++
 

Similar to Curso Javascript profesionales

Similar to Curso Javascript profesionales (20)

Javascript - 2014
Javascript - 2014Javascript - 2014
Javascript - 2014
 
Clase7popu
Clase7popuClase7popu
Clase7popu
 
4. Programación con arrays, funciones, y objetos definidos por el usuario
4. Programación con arrays, funciones, y objetos definidos por el usuario4. Programación con arrays, funciones, y objetos definidos por el usuario
4. Programación con arrays, funciones, y objetos definidos por el usuario
 
Tema2[php]
Tema2[php]Tema2[php]
Tema2[php]
 
Clase 7 objetos globales de javaScript
Clase 7 objetos globales de javaScriptClase 7 objetos globales de javaScript
Clase 7 objetos globales de javaScript
 
Javascript
JavascriptJavascript
Javascript
 
Javascript continuación
Javascript   continuaciónJavascript   continuación
Javascript continuación
 
Php
PhpPhp
Php
 
Javascript objetos
Javascript objetosJavascript objetos
Javascript objetos
 
03. Introduccion a JavaScript y JQuery
03. Introduccion a JavaScript y JQuery03. Introduccion a JavaScript y JQuery
03. Introduccion a JavaScript y JQuery
 
Hack (Lenguaje de Programacion)
Hack (Lenguaje de Programacion)Hack (Lenguaje de Programacion)
Hack (Lenguaje de Programacion)
 
Elementos del Hardware y Software
Elementos del Hardware y SoftwareElementos del Hardware y Software
Elementos del Hardware y Software
 
Java script estructuras_datos
Java script estructuras_datosJava script estructuras_datos
Java script estructuras_datos
 
Ruby intro
Ruby introRuby intro
Ruby intro
 
S6-Contenedores
S6-ContenedoresS6-Contenedores
S6-Contenedores
 
Perl3 subrutinas
Perl3 subrutinasPerl3 subrutinas
Perl3 subrutinas
 
S6-POO-3.2 Contenedores Especiales
S6-POO-3.2 Contenedores EspecialesS6-POO-3.2 Contenedores Especiales
S6-POO-3.2 Contenedores Especiales
 
Charla congreso web introducción programación funcional en JavaScript
Charla congreso web introducción programación funcional en JavaScriptCharla congreso web introducción programación funcional en JavaScript
Charla congreso web introducción programación funcional en JavaScript
 
Java script
Java scriptJava script
Java script
 
OOP-JS pjs
OOP-JS pjsOOP-JS pjs
OOP-JS pjs
 

More from Redradix

Curso desarrollo frontend: HTML - CSS - jQuery
Curso desarrollo frontend: HTML - CSS - jQueryCurso desarrollo frontend: HTML - CSS - jQuery
Curso desarrollo frontend: HTML - CSS - jQueryRedradix
 
Redradix Weekend Textalytics
Redradix Weekend TextalyticsRedradix Weekend Textalytics
Redradix Weekend TextalyticsRedradix
 
Redradix Weekend: Animando sitios web
Redradix Weekend: Animando sitios web Redradix Weekend: Animando sitios web
Redradix Weekend: Animando sitios web Redradix
 
Curso responsive web design - Redradix School
Curso responsive web design  - Redradix SchoolCurso responsive web design  - Redradix School
Curso responsive web design - Redradix SchoolRedradix
 
Redradix school presentation
Redradix school presentationRedradix school presentation
Redradix school presentationRedradix
 
Curso node.js
Curso node.js Curso node.js
Curso node.js Redradix
 
Qué es y como construir un MVP
Qué es y como construir un MVPQué es y como construir un MVP
Qué es y como construir un MVPRedradix
 
Emprender sin riesgos
Emprender sin riesgosEmprender sin riesgos
Emprender sin riesgosRedradix
 
Presentación financiación startups redradix
Presentación financiación startups   redradixPresentación financiación startups   redradix
Presentación financiación startups redradixRedradix
 

More from Redradix (9)

Curso desarrollo frontend: HTML - CSS - jQuery
Curso desarrollo frontend: HTML - CSS - jQueryCurso desarrollo frontend: HTML - CSS - jQuery
Curso desarrollo frontend: HTML - CSS - jQuery
 
Redradix Weekend Textalytics
Redradix Weekend TextalyticsRedradix Weekend Textalytics
Redradix Weekend Textalytics
 
Redradix Weekend: Animando sitios web
Redradix Weekend: Animando sitios web Redradix Weekend: Animando sitios web
Redradix Weekend: Animando sitios web
 
Curso responsive web design - Redradix School
Curso responsive web design  - Redradix SchoolCurso responsive web design  - Redradix School
Curso responsive web design - Redradix School
 
Redradix school presentation
Redradix school presentationRedradix school presentation
Redradix school presentation
 
Curso node.js
Curso node.js Curso node.js
Curso node.js
 
Qué es y como construir un MVP
Qué es y como construir un MVPQué es y como construir un MVP
Qué es y como construir un MVP
 
Emprender sin riesgos
Emprender sin riesgosEmprender sin riesgos
Emprender sin riesgos
 
Presentación financiación startups redradix
Presentación financiación startups   redradixPresentación financiación startups   redradix
Presentación financiación startups redradix
 

Recently uploaded

La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafiosFundación YOD YOD
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfSergioMendoza354770
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx241523733
 
El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son241514984
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadMiguelAngelVillanuev48
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMidwarHenryLOZAFLORE
 
FloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptxFloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptx241522327
 
R1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaR1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaarkananubis
 
Hernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxHernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxJOSEMANUELHERNANDEZH11
 
dokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptdokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptMiguelAtencio10
 
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxGoogle-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxAlexander López
 
Arenas Camacho-Practica tarea Sesión 12.pptx
Arenas Camacho-Practica tarea Sesión 12.pptxArenas Camacho-Practica tarea Sesión 12.pptx
Arenas Camacho-Practica tarea Sesión 12.pptxJOSEFERNANDOARENASCA
 
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6    CREAR UN RECURSO MULTIMEDIAActividad integradora 6    CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA241531640
 
definicion segun autores de matemáticas educativa
definicion segun autores de matemáticas  educativadefinicion segun autores de matemáticas  educativa
definicion segun autores de matemáticas educativaAdrianaMartnez618894
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptJavierHerrera662252
 
Segunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxSegunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxMariaBurgos55
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxaylincamaho
 
Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..RobertoGumucio2
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxAlexander López
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxAlexander López
 

Recently uploaded (20)

La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafios
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx
 
El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidad
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptx
 
FloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptxFloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptx
 
R1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en minaR1600G CAT Variables de cargadores en mina
R1600G CAT Variables de cargadores en mina
 
Hernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptxHernandez_Hernandez_Practica web de la sesion 11.pptx
Hernandez_Hernandez_Practica web de la sesion 11.pptx
 
dokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.pptdokumen.tips_36274588-sistema-heui-eui.ppt
dokumen.tips_36274588-sistema-heui-eui.ppt
 
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptxGoogle-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
Google-Meet-como-herramienta-para-realizar-reuniones-virtuales.pptx
 
Arenas Camacho-Practica tarea Sesión 12.pptx
Arenas Camacho-Practica tarea Sesión 12.pptxArenas Camacho-Practica tarea Sesión 12.pptx
Arenas Camacho-Practica tarea Sesión 12.pptx
 
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6    CREAR UN RECURSO MULTIMEDIAActividad integradora 6    CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
 
definicion segun autores de matemáticas educativa
definicion segun autores de matemáticas  educativadefinicion segun autores de matemáticas  educativa
definicion segun autores de matemáticas educativa
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
 
Segunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptxSegunda ley de la termodinámica TERMODINAMICA.pptx
Segunda ley de la termodinámica TERMODINAMICA.pptx
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
 
Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..Plan Sarmiento - Netbook del GCBA 2019..
Plan Sarmiento - Netbook del GCBA 2019..
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
 

Curso Javascript profesionales