curso javascript profesionales
DESCRIPTION
Documentación curso Javascript para profesionales por Redradix School. Curso avanzado de Javascript.TRANSCRIPT
![Page 1: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/1.jpg)
![Page 2: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/2.jpg)
Javascript para Profesionales
made with love by Redradix (www.redradix.com)
![Page 3: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/3.jpg)
Fundamentos
![Page 4: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/4.jpg)
Objetos
! Conjunto de propiedades propias + heredadas de otro objeto (prototipos)
! ¡Qué no cunda el pánico!
![Page 5: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/5.jpg)
Objetos
! Dinámicos
! Set de strings
var obj = {};obj.nuevaPropiedad = 1;delete obj.nuevaPropiedad;
var strset = { hola: true, adios: true};"hola" in strset;
![Page 6: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/6.jpg)
Objetos
! Referencias
! Todo son objetos excepto: strings, números, booleans, null o undefined
! Strings, números y booleans se comportan como objetos inmutables
var p1 = {x: 1}, p2 = p1;
p1 === p2; // truep1.x = 5;p2.x; // 5
![Page 7: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/7.jpg)
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();
![Page 8: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/8.jpg)
Objetos
! Literales
- clase: Object
- sencillos y ligeros
! Construidos
- clase: prototype
- constructor
{ un: "objeto", literal: true};
new NombreDeUnaFuncion();
![Page 9: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/9.jpg)
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.
![Page 10: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/10.jpg)
Clases
Si esto es un “punto”
Y esto es otro “punto”
¿Qué es esto?
¿Y esto?
var point = {x: 0, y: 0};
var point2 = {x: 5, y: 5};
var what = {x: 10, y: 10};
var isit = {x: -10, y: -20};
![Page 11: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/11.jpg)
Mensajes
• Teniendo:
• ¿Que significa esto?
var obj = { nombre: "Pepito", saludo: function () { return "Hola, Mundo!"; }};
obj.nombre;
![Page 12: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/12.jpg)
Mensajes
• Teniendo:
• ¿Y esto?
var obj = { nombre: "Pepito", saludo: function () { return "Hola, Mundo!"; }};
obj.saludo;
![Page 13: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/13.jpg)
Mensajes
• Teniendo:
• ¿Y esto otro? (¡cuidado!)
var obj = { nombre: "Pepito", saludo: function () { return "Hola, Mundo!"; }};
obj[“saludo”]();
![Page 14: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/14.jpg)
Mensajes
• Teniendo:
• ¿Es lo mismo?
var obj = { nombre: "Pepito", saludo: function () { return "Hola, Mundo!"; }};
var fn = obj["saludo"];fn();
![Page 15: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/15.jpg)
Mensajes
• Teniendo:
• ¡NO es no mismo!
var obj = { nombre: "Pepito", saludo: function () { return "Hola, Mundo!"; }};
var fn = obj["saludo"];fn();
![Page 16: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/16.jpg)
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(...) y apply(...)
(function() { alert("Hey!"); })();
objeto.metodo();
new MiConstructor();
fn.call({}, "param");
![Page 17: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/17.jpg)
Mensajes
- Invocando directamente la función
- Enviando un mensaje a un objeto (método)
(function() { alert("Hey!"); })();
objeto.metodo();
![Page 18: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/18.jpg)
Mensajes
Un mensaje se envía a un receptor
var obj = {};obj.toString(); // [object Object]
"hola don Pepito".toUpperCase();
![Page 19: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/19.jpg)
Mensajes
Un mensaje se envía a un receptor
var obj = {};obj.toString(); // [object Object]
"hola don Pepito".toUpperCase();
![Page 20: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/20.jpg)
Mensajes
La sintaxis es engañosa
var obj = { coleccion: ["uno", "dos", "tres"], metodo: function() { return "Hola, Mundo!"; }};
obj.coleccion[1]; obj.metodo();vs.
![Page 21: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/21.jpg)
Mensajes
obj.metodo();var fn = obj.metodo;fn();
![Page 22: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/22.jpg)
Mensajes
obj.metodo();var fn = obj.metodo;fn();
- Accede a la propiedad “metodo” de obj
- Supongo que es una función y la invoco
![Page 23: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/23.jpg)
Mensajes
obj.metodo();var fn = obj.metodo;fn();
- Accede a la propiedad “metodo” de obj
- Supongo que es una función y la invoco
- Envía el mensaje “metodo” a obj
- Si existe, obj se encarga de ejecutar la función
![Page 24: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/24.jpg)
Mensajes
obj.metodo();var fn = obj.metodo;fn();
- Accede a la propiedad “metodo” de obj
- Supongo que es una función y la invoco
- NO HAY RECEPTOR
- Envía el mensaje “metodo” a obj
- Si existe, obj se encarga de ejecutar la función
- obj ES EL RECEPTOR
![Page 25: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/25.jpg)
Mensajes
Un error típico:
$("#elemento").click(objeto.clickHandler);
![Page 26: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/26.jpg)
Mensajes
Un error típico:
• Lo que se intenta decir:
- “Al hacer click sobre #elemento, envía el mensaje clickHandler a objeto”
$("#elemento").click(objeto.clickHandler);
![Page 27: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/27.jpg)
Mensajes
Un error típico:
• 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”
$("#elemento").click(objeto.clickHandler);
![Page 28: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/28.jpg)
El receptor: ...
¿Por qué tanto lío con el receptor del mensaje?
![Page 29: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/29.jpg)
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
![Page 30: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/30.jpg)
El receptor: this
this = “el receptor de este mensaje”
var nombre = "Sonia";
var obj = { nombre: "Pepito", saludo: function() { alert("hola " + this.nombre); }}
obj.saludo();
![Page 31: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/31.jpg)
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
![Page 32: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/32.jpg)
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();
![Page 33: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/33.jpg)
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();
![Page 34: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/34.jpg)
El receptor: this
Semánticamente, es como un parámetro oculto
que el receptor se encargara de proveer
function ([this]) { alert("hola " + this.nombre);}
obj.saludo(); => saludo([obj]);
![Page 35: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/35.jpg)
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();
![Page 36: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/36.jpg)
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]);
![Page 37: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/37.jpg)
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]);
![Page 38: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/38.jpg)
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)
![Page 39: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/39.jpg)
El receptor: this
Otro error común:
var obj = { clicks: 0, init: function() { $("#element").click(function() { this.clicks += 1; }); }};
obj.init();
![Page 40: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/40.jpg)
El receptor: this
Otro error común:
var obj = { clicks: 0, init: function([this]) { $("#element").click(function([this]) { this.clicks += 1; }); }};
obj.init([obj]);
![Page 41: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/41.jpg)
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();
![Page 42: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/42.jpg)
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(...) y apply(...)
(function() { alert("Hey!"); })();
objeto.metodo();
new MiConstructor();
fn.call({}, "param");
![Page 43: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/43.jpg)
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(...) y apply(...)
fn.call({}, "param");
![Page 44: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/44.jpg)
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étodosvar fn = function() { alert("Hey!"); };
fn.toString();
![Page 45: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/45.jpg)
El receptor: this
• Dos métodos permiten manipular el receptor (contexto):
- fn.call(context [, arg1 [, arg2 [...]]])
- fn.apply(context, arglist)
var a = [1,2,3];Array.prototype.slice.call(a, 1, 2); // [2]
var a = [1,2,3];Array.prototype.slice.apply(a, [1, 2]); // [2]
![Page 46: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/46.jpg)
El receptor: this
var nombre = "Objeto Global";
function saluda() { alert("Hola! Soy " + this.nombre);}
var alicia = { nombre: "Alicia"};
saluda();
saluda.call(alicia);
![Page 47: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/47.jpg)
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);
![Page 48: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/48.jpg)
arguments
• Se comporta (más o menos) como Array...
• ...pero NO del todo
function echoArgs() { alert(arguments[0]); // 1}
echoArgs(1, 2, 3, 4);
function echoArgs() { return arguments.slice(0, 1); // Error!}
echoArgs(1, 2, 3, 4);
![Page 49: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/49.jpg)
arguments
• Un truco:
function echoArgs() { var slice = Array.prototype.slice; return slice.call(arguments, 0, 1);}
echoArgs(1, 2, 3, 4); // [1]
![Page 50: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/50.jpg)
arguments
¡Cuidado, se comporta como parámetro oculto!
function exterior() { var interior = function() { alert(arguments.length); }; interior();}
exterior("a", "b", "c");
![Page 51: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/51.jpg)
intermedio: this y arguments
¿Qué hace esta función?
function misterio(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
![Page 52: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/52.jpg)
Intermedio: this y arguments
function misterio(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
var algo = misterio();
typeof algo; // ???
![Page 53: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/53.jpg)
Intermedio: this y arguments
function misterio(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
var algo = misterio();
algo(); // ???
![Page 54: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/54.jpg)
Intermedio: this y arguments
function misterio(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
var algo = misterio({}, function() { return this;});
typeof algo(); // ???
![Page 55: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/55.jpg)
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(); // ???
![Page 56: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/56.jpg)
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(); // ???
![Page 57: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/57.jpg)
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(); /// ???
![Page 58: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/58.jpg)
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, "); /// ???
![Page 59: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/59.jpg)
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, "); /// ???
![Page 60: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/60.jpg)
Intermedio: this y arguments
• bind: fija una función a un contexto
function bind(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
![Page 61: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/61.jpg)
Intermedio: this y arguments
Volviendo al problema:
var obj = { clicks: 0, init: function() { $("#element").click(function() {
// MAL this.clicks += 1; }); }};
obj.init();
![Page 62: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/62.jpg)
Intermedio: this y arguments
Apaño:
var obj = { clicks: 0, init: function() { var that = this; $("#element").click(function() { that.clicks += 1; }); }};
obj.init();
![Page 63: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/63.jpg)
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();
![Page 64: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/64.jpg)
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(); }); }};
![Page 65: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/65.jpg)
Intermedio: this y arguments
• bind al rescate
var obj = { clicks: 0, incClicks: function() { this.clicks += 1; }, init: function() { $("#element").click( bind(this, this.incClicks) ); }};
![Page 66: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/66.jpg)
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)); };}
![Page 67: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/67.jpg)
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(); // ???
![Page 68: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/68.jpg)
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(); // ???
![Page 69: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/69.jpg)
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(); // ???
![Page 70: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/70.jpg)
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"); // ???
![Page 71: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/71.jpg)
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(); // ???
![Page 72: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/72.jpg)
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(); // ???
![Page 73: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/73.jpg)
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"); // ???
![Page 74: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/74.jpg)
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); // ???
![Page 75: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/75.jpg)
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)); };}
![Page 76: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/76.jpg)
Intermedio: rizar el rizo
var unObj = { nombre: "Manuel", edad: 32};
function getNombre() { return this.nombre; }function setNombre(nombre) { this.nombre = nombre; }function getEdad() { return this.edad; }function setEdad(edad) { this.edad = edad; }
var bindToUnObj = curry(bind, unObj), getUnObjNombre = bindToUnObj(getNombre), setUnObjNombre = bindToUnObj(setNombre);
setUnObjNombre("Pepito");getUnObjNombre(); // ???
![Page 77: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/77.jpg)
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(); // ???
![Page 78: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/78.jpg)
Prototipos
![Page 79: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/79.jpg)
Prototipos
• ¿Por qué tan mala fama?
• ¡Es un mecanismo muy sencillo!
• Distinto a otros lenguajes
![Page 80: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/80.jpg)
Prototipos
Un objeto obj:
qué pasa si hacemos:
var obj = {uno: 1, dos: 2};
obj.uno; // 1
![Page 81: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/81.jpg)
Prototipos
var obj = {uno: 1, dos: 2};
obj.uno; // 1
uno 1
dos 2
uno 1
dos 2
obj
obj
![Page 82: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/82.jpg)
Prototipos
Si hacemos:
var obj = {uno: 1, dos: 2};
obj.tres; // undefined
uno 1
dos 2
obj
objuno 1dos 2
Not found! undefined
![Page 83: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/83.jpg)
Prototipos
¿De dónde sale?
var obj = {uno: 1, dos: 2};
obj.toString(); // '[object Object]'
uno 1
dos 2
obj
objuno 1dos 2
Not found! undefined
¿?
![Page 84: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/84.jpg)
Prototipos
obj.toString(); // '[object Object]'
objuno 1
dos 2
prototype Object
toString functionvalueOf function
...Not found! undefined
Object
![Page 85: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/85.jpg)
Prototipos
Teniendo:
auno 1dos 2
prototype b
toString functionvalueOf function
...Not found! undefine
d
Objectbtres 3
cuatro 4prototype Object
![Page 86: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/86.jpg)
Prototipos
auno 1dos 2
prototype b
toString functionvalueOf function
...Not found! undefine
d
Objectbtres 3
cuatro 4prototype Object
a.uno; // 1
![Page 87: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/87.jpg)
Prototipos
auno 1dos 2
prototype b
toString functionvalueOf function
...Not found! undefine
d
Objectbtres 3
cuatro 4prototype Object
a.cuatro; // 4
![Page 88: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/88.jpg)
Prototipos
auno 1dos 2
prototype b
toString functionvalueOf function
...Not found! undefine
d
Objectbtres 3
cuatro 4prototype Object
a.toString; // [object Object]
![Page 89: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/89.jpg)
Prototipos
auno 1dos 2
prototype b
toString functionvalueOf function
...Not found! undefine
d
Objectbtres 3
cuatro 4prototype Object
a.noExiste; // undefined
![Page 90: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/90.jpg)
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!
![Page 91: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/91.jpg)
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(...) y apply(...)
(function() { alert("Hey!"); })();
objeto.metodo();
new MiConstructor();
fn.call({}, "param");
![Page 92: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/92.jpg)
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();
![Page 93: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/93.jpg)
Constructores
• Funciones
• Invocación precedida por new
• Su contexto es un objeto recién generado
• return implícito
• La única manera de manipular prototipos
![Page 94: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/94.jpg)
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"
![Page 95: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/95.jpg)
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"
![Page 96: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/96.jpg)
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
![Page 97: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/97.jpg)
Constructores
var b = { uno: 1, dos: 2};
function A() { this.tres = 3; this.cuatro = 4;}
A.prototype = b;
var instancia = new A();instancia.tres; // 3instancia.uno; // 1
![Page 98: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/98.jpg)
Constructores
var b = { uno: 1, dos: 2};
function A() { this.tres = 3; this.cuatro = 4;}
A.prototype = b;
var instancia = new A();instancia.tres; // 3instancia.uno; // 1
instanciauno 1dos 2
proto b
btres 3
cuatro 4proto Object
![Page 99: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/99.jpg)
Constructores
.hasOwnProperty(name)• Distinguir las propiedades heredadas de las propias
• true solo si la propiedad es del objeto
instancia.hasOwnProperty("tres"); // trueinstancia.hasOwnProperty("uno"); // false
![Page 100: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/100.jpg)
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; // ???
![Page 101: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/101.jpg)
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; // ???
![Page 102: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/102.jpg)
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; // ???
![Page 103: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/103.jpg)
Constructores
pepenombre “Pepe”
proto comun
comunempresa “ACME”
proto Object
var pepe = new Empleado("Pepe");
![Page 104: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/104.jpg)
Constructores
pepenombre “Pepe”
proto comun
comunempresa “Googlezone”
proto Object
comun.empresa = "Googlezon";
![Page 105: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/105.jpg)
Constructores
pepenombre “Pepe”
proto comun
comunempresa “Googlezone”
proto Object
antonionombre “Antonio”
proto comun
var antonio = new Empleado("Antonio");
![Page 106: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/106.jpg)
Constructores
pepenombre “Pepe”
proto comun
comunempresa “Googlezone”
proto Object
antonionombre “Antonio”
proto comun
pepe.empresa;
![Page 107: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/107.jpg)
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)!
![Page 108: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/108.jpg)
Intermedio: constructores
¿Cómo hacer que C herede de B que hereda de A?
![Page 109: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/109.jpg)
Intermedio: constructores
¿Cómo hacer que C herede de B que hereda de A?
Cuno 1
proto B
tres 3
proto Object
ABdos 2
proto A
var instancia = new C();instancia.tres; // 3
![Page 110: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/110.jpg)
Intermedio: constructores
function C() { this.uno = 1;}
var instancia = new C();instancia.tres;
![Page 111: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/111.jpg)
Intermedio: constructores
var B = {dos: 2};
function C() { this.uno = 1;}
C.prototype = B;
var instancia = new C();instancia.tres;
![Page 112: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/112.jpg)
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;
![Page 113: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/113.jpg)
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; // !!!
![Page 114: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/114.jpg)
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; // ???
![Page 115: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/115.jpg)
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;
![Page 116: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/116.jpg)
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;
![Page 117: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/117.jpg)
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!
![Page 118: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/118.jpg)
Mecanismos de herencia
![Page 119: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/119.jpg)
Mecanismos de herencia
• Herencia clásica
• Herencia de prototipos
• Mixins (módulos)
• Extra: herencia funcional
![Page 120: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/120.jpg)
Herencia clásica
¿Qué significa?
• Clases!
• El tipo de herencia más común en otros lenguajes
• Encapsulado y visibilidad
![Page 121: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/121.jpg)
Herencia clásica
Vamos a empezar por un constructor:
function MiClase() { // ???}
var instancia = new MiClase();
![Page 122: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/122.jpg)
Herencia clásica
Las propiedades (públicas)
function MiClase() { this.unaPropiedad = "valor"; this.otraPropiedad = "otro valor";}
var instancia = new MiClase();
![Page 123: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/123.jpg)
Herencia clásica
¿Métodos?
![Page 124: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/124.jpg)
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();
![Page 125: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/125.jpg)
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();
![Page 126: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/126.jpg)
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);};
![Page 127: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/127.jpg)
Herencia clásica
¿Cómo se pueden crear métodos “de clase”?
MiClase.metodoEstatico("hola!");
![Page 128: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/128.jpg)
Herencia clásica
¿Cómo se pueden crear métodos “de clase”?
¡Los constructores son objetos!
MiClase.metodoEstatico("hola!");
MiClase.metodoEstatico = function(cadena) { console.log("metodoEstatico:", cadena);}
![Page 129: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/129.jpg)
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:
![Page 130: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/130.jpg)
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:
• ¡No es fácil invocar al super constructor!
![Page 131: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/131.jpg)
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;}
![Page 132: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/132.jpg)
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!
![Page 133: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/133.jpg)
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!
![Page 134: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/134.jpg)
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!
crea glob. especie!
![Page 135: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/135.jpg)
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!
![Page 136: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/136.jpg)
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!
ERROR!
![Page 137: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/137.jpg)
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!
![Page 138: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/138.jpg)
Herencia clásica: Cuidado!
Este esquema tiene varios problemas:
• ¡No es fácil invocar al super constructor!
• No es fácil encapsular
![Page 139: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/139.jpg)
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();
![Page 140: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/140.jpg)
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!
![Page 141: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/141.jpg)
Herencia clásica: Cuidado!
function Superclase() { operacionMuyCostosa(); alert(“Oh, no!”);}
function MiClase() { // ...}MiClase.prototype = new Superclase();
![Page 142: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/142.jpg)
Herencia clásica?
¿Qué se puede hacer?
![Page 143: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/143.jpg)
Herencia clásica?
Hay dos enfoques:
![Page 144: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/144.jpg)
Herencia clásica?
Hay dos enfoques:
• El simple
![Page 145: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/145.jpg)
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;}
![Page 146: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/146.jpg)
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;
![Page 147: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/147.jpg)
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!
![Page 148: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/148.jpg)
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
![Page 149: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/149.jpg)
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; };
![Page 150: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/150.jpg)
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; };
![Page 151: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/151.jpg)
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);
![Page 152: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/152.jpg)
Herencia clásica?
Hay dos enfoques:
• El simple
• El cómodo
![Page 153: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/153.jpg)
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!"); }});
![Page 154: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/154.jpg)
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!"); }});
![Page 155: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/155.jpg)
Intermedio: klass.js
¡Rellena los huecos!
var Class = function(){};
Class.extend = function(prop) { var _super = this.prototype;
// ...
return Klass;};
![Page 156: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/156.jpg)
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!
![Page 157: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/157.jpg)
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”
![Page 158: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/158.jpg)
Herencia de prototipos
Vamos a cambiar de marcha...
![Page 159: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/159.jpg)
Herencia de prototipos
Vamos a cambiar de marcha...
¡Ahora, sin clases!
![Page 160: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/160.jpg)
Herencia de prototipos
Vamos a cambiar de marcha...
¡Ahora, sin clases!
¿¿Cómo puede haber POO sin clases??
![Page 161: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/161.jpg)
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!
![Page 162: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/162.jpg)
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!
![Page 163: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/163.jpg)
Herencia de prototipos
var benito = { nombre: "Benito", edad: 36, profesión: "jardinero", saludar: function() { alert("Buen día!"); }, envejecer: function() { this.edad += 1; }};
![Page 164: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/164.jpg)
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!
![Page 165: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/165.jpg)
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!
![Page 166: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/166.jpg)
Herencia de prototipos
También se puede generalizarvar 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";
![Page 167: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/167.jpg)
Herencia de prototipos
¡Así de simple!
function clone(obj) { function F(){} F.prototype = obj; return new F();}
![Page 168: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/168.jpg)
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
![Page 169: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/169.jpg)
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!
![Page 170: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/170.jpg)
Herencia de prototipos
¿Cuál uso?
![Page 171: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/171.jpg)
Herencia de prototipos
¿Cuál uso?
¡Las dos!
![Page 172: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/172.jpg)
Intermedio: prototipos
¿Qué significa?
objeto.propiedad;
![Page 173: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/173.jpg)
Intermedio: prototipos
¿Qué significa?
“Accede a la propiedad propiedad del objeto objeto”
objeto.propiedad;
![Page 174: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/174.jpg)
Intermedio: prototipos
¿Qué significa?
“Accede a la propiedad propiedad del objeto objeto. Si no la encuentras, sigue buscando por la cadena de prototipos.”
objeto.propiedad;
![Page 175: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/175.jpg)
Intermedio: prototipos
¿Qué significa?
objeto.propiedad = 1;
![Page 176: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/176.jpg)
Intermedio: prototipos
¿Qué significa?
“Guarda el valor 1 en la propiedad propiedad del objeto objeto.”
objeto.propiedad = 1;
![Page 177: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/177.jpg)
Intermedio: prototipos
¿Qué significa?
“Guarda el valor 1 en la propiedad propiedad del objeto objeto. Si no la encuentras, créala!”
objeto.propiedad = 1;
![Page 178: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/178.jpg)
Intermedio: prototipos
peso 1
proto Object
plumaplomoproto pluma
var pluma = { peso: 1};
var plomo = clone(pluma);
![Page 179: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/179.jpg)
Intermedio: prototipos
peso 1
proto Object
plumaplomoproto pluma
plomo.peso; // 1
![Page 180: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/180.jpg)
Intermedio: prototipos
peso 1
proto Object
plumaplomoproto pluma
peso 100
plomo.peso = 100;
![Page 181: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/181.jpg)
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.
![Page 182: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/182.jpg)
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;
![Page 183: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/183.jpg)
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;
![Page 184: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/184.jpg)
¡Se acabaron los prototipos!
![Page 185: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/185.jpg)
Clausuras
Sólo una idea importante más: ámbitos
![Page 186: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/186.jpg)
Clausuras
• Una idea sencilla, pero difícil de explicar
• Están por todas partes
• Consecuencia natural del lenguaje
• ¡Muy útiles!
![Page 187: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/187.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
![Page 188: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/188.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();typeof fn;
![Page 189: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/189.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();fn(); // ???
![Page 190: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/190.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();fn();
fn = function() { return a;}
![Page 191: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/191.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();fn();
fn = function() { return a;}
![Page 192: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/192.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();fn();
fn = function() { return a;}
![Page 193: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/193.jpg)
Clausuras
function clausurator() { var a = 1; return function() { return a; };}
var fn = clausurator();fn();
fn = function() { return a;}
a = 1;
![Page 194: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/194.jpg)
Clausuras
Otro caso:function makeContador() { var i = 0; return function() { return i++; }}
var contador1 = makeContador();contador1(); // ???contador1(); // ???
var contador2 = makeContador();contador2(); // ???
![Page 195: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/195.jpg)
Clausuras
Otro caso:function makeContador() { var i = 0; return function() { return i++; }}
var contador1 = makeContador();contador1(); // 0contador1(); // 1
var contador2 = makeContador();contador2(); // 0
![Page 196: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/196.jpg)
Clausuras
function makeContador() { var i = 0; return function() { return i++; }}
var contador1 = makeContador();contador1(); // 0contador1(); // 1
var contador2 = makeContador();contador2(); // 0
contador1 = function() { return i++;}
i = 0;
![Page 197: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/197.jpg)
Clausuras
function makeContador() { var i = 0; return function() { return i++; }}
var contador1 = makeContador();contador1(); // 0contador1(); // 1
var contador2 = makeContador();contador2(); // 0
contador1 = function() { return i++;}
i = 1;
![Page 198: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/198.jpg)
Clausuras
function makeContador() { var i = 0; return function() { return i++; }}
var contador1 = makeContador();contador1(); // 0contador1(); // 1
var contador2 = makeContador();contador2(); // 0
contador1 = function() { return i++;}
i = 1;
contador2 = function() { return i++;}
i = 0;
![Page 199: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/199.jpg)
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(); // ???
![Page 200: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/200.jpg)
Clausuras
• bind: fija una función a un contexto
function bind(ctx, fn) { return function() { return fn.apply(ctx, arguments); }}
![Page 201: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/201.jpg)
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)); };}
![Page 202: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/202.jpg)
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!
![Page 203: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/203.jpg)
Intermedio: herencia funcional
function PseudoConstructor() { var self = {}; self.propiedad = "valor"; return self;}
var pseudoInstancia = PseudoConstructor();pseudoInstancia.propiedad; // "valor"
![Page 204: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/204.jpg)
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");
![Page 205: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/205.jpg)
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");
![Page 206: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/206.jpg)
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");
![Page 207: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/207.jpg)
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
![Page 208: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/208.jpg)
Intermedio: herencia funcional
¿Y para heredar?
![Page 209: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/209.jpg)
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
![Page 210: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/210.jpg)
Intermedio: herencia funcional
¿Cómo llamar al supermétodo?
![Page 211: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/211.jpg)
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;}
![Page 212: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/212.jpg)
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
![Page 213: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/213.jpg)
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!
![Page 214: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/214.jpg)
Programación Funcional
made with love by Redradix (www.redradix.com)
![Page 215: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/215.jpg)
¿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
![Page 216: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/216.jpg)
Funciones de orden superior
Funciones que devuelven funciones
• curry
• bind
• ¡Muchas otras!
![Page 217: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/217.jpg)
Funciones de orden superior
Algunas de las más útiles:
• throttle
• debounce
• once
• after
• compose
• memoize
![Page 218: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/218.jpg)
throttle
Controlar la frecuencia de invocación
• La función se invocará como máximo una vez
• Durante el periodo de tiempo especificado
![Page 219: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/219.jpg)
throttle
var counter = 0, inc = function() { counter++; };
inc = throttle(inc, 10);
for (var i=100000; i--;) { inc();}
alert(counter); // ~6
![Page 220: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/220.jpg)
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); } }}
![Page 221: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/221.jpg)
debounce
Ejecutar la función cuando se deje de llamar
• La llamada se pospone hasta que pasen x ms
• Desde la última invocación
![Page 222: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/222.jpg)
debounce
var counter = 0, inc = function() { counter++; alert(counter); };
inc = debounce(inc, 1000);
for (var i=100000; i--;) { inc();}
![Page 223: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/223.jpg)
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); }}
![Page 224: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/224.jpg)
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);
![Page 225: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/225.jpg)
once
function once(fn) { var executed = false; return function() { if (!executed) { executed = true; return fn.apply(this, arguments); } }}
![Page 226: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/226.jpg)
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);
![Page 227: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/227.jpg)
after
function after(fn, n) { var times = 0; return function() { times++; if (times % n == 0) { return fn.apply(this, arguments); } }}
![Page 228: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/228.jpg)
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());
![Page 229: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/229.jpg)
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; }}
![Page 230: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/230.jpg)
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
![Page 231: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/231.jpg)
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);
![Page 232: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/232.jpg)
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]; }}
![Page 233: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/233.jpg)
Asincronía
JS es, por naturaleza, asíncrono
• Eventos
• AJAX
• Carga de recursos
![Page 234: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/234.jpg)
Asincronía
¿Qué significa asíncrono?
function asincrona() { var random = Math.floor(Math.random() * 100); setTimeout(function() { return random; }, random);}
![Page 235: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/235.jpg)
Asincronía
¿Cómo devuelvo el valor random desde dentro?
function asincrona() { var random = Math.floor(Math.random() * 100); setTimeout(function() { return random; }, random);}
![Page 236: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/236.jpg)
Asincronía
function asincrona(callback) { var random = Math.floor(Math.random() * 1000); setTimeout(function() { callback(random); }, random);}
asincrona(function(valor) { alert(valor);});
![Page 237: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/237.jpg)
Asincronía
function asincrona(callback) { var random = Math.floor(Math.random() * 1000); setTimeout(function() { callback(random); }, random);}
asincrona(function(valor) { alert(valor);});
![Page 238: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/238.jpg)
Asincronía
function asincrona(callback) { var random = Math.floor(Math.random() * 1000); setTimeout(function() { callback(random); }, random);}
asincrona(function(valor) { alert(valor);});
![Page 239: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/239.jpg)
Asincronía
Promesas
• Otra forma de escribir código asíncrono
• Más fácil de manipular
• Más fácil de combinar
![Page 240: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/240.jpg)
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
![Page 241: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/241.jpg)
Promesas
function onSuccess(data) { /* ... */ }
function onFailure(e) { /* ... */}
var promesa = $.get('/mydata');promesa.then(onSuccess, onFailure);
![Page 242: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/242.jpg)
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
![Page 243: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/243.jpg)
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
![Page 244: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/244.jpg)
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. }});
![Page 245: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/245.jpg)
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.});
![Page 246: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/246.jpg)
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.});
![Page 247: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/247.jpg)
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);});
![Page 248: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/248.jpg)
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);});
![Page 249: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/249.jpg)
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!");});
![Page 250: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/250.jpg)
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...");});
![Page 251: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/251.jpg)
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);});
![Page 252: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/252.jpg)
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);});
![Page 253: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/253.jpg)
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);});
![Page 254: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/254.jpg)
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);});
![Page 255: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/255.jpg)
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! */});
![Page 256: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/256.jpg)
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! */});
![Page 257: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/257.jpg)
Promesas
¿Cómo creo una promesa?
![Page 258: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/258.jpg)
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
![Page 259: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/259.jpg)
Promesas
Promesa DiferidoRepresenta un valor futuro
Controla la generación del valor
onSuccess resolve(valor)
onFailure reject(error)
![Page 260: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/260.jpg)
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());});
![Page 261: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/261.jpg)
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
![Page 262: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/262.jpg)
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
![Page 263: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/263.jpg)
Promesas
Deferred#promise()• Devuelve la promesa asociada al diferido
![Page 264: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/264.jpg)
Promesas
Deferred#then(onSuccess, onFailure)• Exactamente igual que hacer: deferred.promise().then(...);
![Page 265: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/265.jpg)
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
![Page 266: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/266.jpg)
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
![Page 267: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/267.jpg)
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
![Page 268: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/268.jpg)
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
![Page 269: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/269.jpg)
Promesas
R.Deferred.when(1, 2, 3).then(function(a, b, c) { console.log(a, b, c); // 1 2 3});
![Page 270: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/270.jpg)
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);
![Page 271: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/271.jpg)
Promesas
/* Homogeneizar */
var promesaOValor = noSeQueDevuelve();
R.Deferred.when(promesaOValor).then(function(valor) { console.log(valor);});
![Page 272: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/272.jpg)
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);
![Page 273: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/273.jpg)
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");
![Page 274: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/274.jpg)
Promesas
Implementa R.Deferred.when()• tema2/when/index.html
![Page 275: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/275.jpg)
Patrones y principios de diseño
made with love by Redradix (www.redradix.com)
![Page 276: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/276.jpg)
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.)
![Page 277: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/277.jpg)
SRP
Es común ver cosas como esta:
$.ajax({ ... }) .success(function() { cambioEnInterfaz(); mostrarModal(); if ($("#elemento").value() == "Ok") { /* ... */ } globalSeHaGuardado = true; }) .error(function() { // ... });
![Page 278: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/278.jpg)
SRP
O como esta:
var Widget = Class.extend({ onClick: function() { ... }, guardar: function() { ... }, render: function() { ... }, mostrarError: function() { ... }});
![Page 279: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/279.jpg)
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() { ... }});
![Page 280: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/280.jpg)
SRP
Caso práctico: masonry.js
• https://github.com/desandro/masonry/blob/master/jquery.masonry.js
• en el método _create (línea 102)...
![Page 281: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/281.jpg)
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();!!!!!!!!});!!!!!!}
![Page 282: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/282.jpg)
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();!!!!!!!!});!!!!!!}
![Page 283: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/283.jpg)
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
![Page 284: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/284.jpg)
SRP
Caso práctico: BrowserQuest
• https://github.com/mozilla/BrowserQuest/blob/master/client/js/chest.js
![Page 285: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/285.jpg)
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;!!!!!!!!}!!!!});
![Page 286: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/286.jpg)
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
![Page 287: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/287.jpg)
SRP
Caso práctico: Backbone.js
• https://github.com/documentcloud/backbone/blob/master/backbone.js
• en Backbone.Model, línea 179...
![Page 288: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/288.jpg)
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”)
![Page 289: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/289.jpg)
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
![Page 290: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/290.jpg)
Principios de diseño
• Tell, Don’t Ask
- “Dime lo que necesitas”
- Claridad y expresividad
- Encapsular las comprobaciones
![Page 291: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/291.jpg)
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)];!!!!!!!!!!!!!!!!!!!!}
![Page 292: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/292.jpg)
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)];!!!!!!!!!!!!!!!!!!!!}
![Page 293: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/293.jpg)
Tell, Don’t Ask
Programación:
• Estructurada: adquiere info y toma decisiones
• OO: manda a los objetos hacer cosas
![Page 294: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/294.jpg)
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
![Page 295: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/295.jpg)
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!
![Page 296: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/296.jpg)
Tell, Don’t Ask
if (usuario.primerLogin) { usuario.mostrarMensajeBienvenida();} else { usuario.mostrarSaludo();}
![Page 297: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/297.jpg)
Tell, Don’t Ask
var Usuario = Class.extend({ saludar: function() { if (this.primerLogin) { this.mostrarMensajeBienvenida(); } else { this.mostrarSaludo(); } }});
// y después...
usuario.saludar();
![Page 298: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/298.jpg)
Tell, Don’t Ask
function comprobarTimeout(respuesta) { if ((Date.now() - respuesta.start) > 10000) { respuesta.notificarTimeout(); }}
![Page 299: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/299.jpg)
Tell, Don’t Ask
var Respuesta = Class.extend({ comprobarTimeout: function() { if ((Date.now() - this.start) > 10000) { this.notificarTimeout(); } }});
// y después...
respuesta.comprobarTimeout();
![Page 300: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/300.jpg)
Tell, Don’t Ask
var elementos = miColeccion.getItems();for (var i=0; i<elementos.length; i++) { var elemento = elementos[i]; console.log(elemento.nombre);}
![Page 301: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/301.jpg)
Tell, Don’t Ask
miColeccion.forEach(function(e) { console.log(e.nombre);});
![Page 302: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/302.jpg)
Tell, Don’t Ask
var elemento = new Elemento("hola", 12);var lista = miColeccion.getItems();lista.addElementAt(elemento.getOrder(), elemento);
![Page 303: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/303.jpg)
Tell, Don’t Ask
var elemento = new Elemento("hola", 12);miColeccion.add(elemento);
![Page 304: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/304.jpg)
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!
![Page 305: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/305.jpg)
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
![Page 306: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/306.jpg)
Principios de diseño
• S.O.L.I.D.
- Single Responsibility
- Open-Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
![Page 307: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/307.jpg)
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
![Page 308: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/308.jpg)
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();
![Page 309: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/309.jpg)
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();
![Page 310: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/310.jpg)
Open-Closed
Pretende:
• Promover el uso de abstracciones
• Código modular y flexible ante el cambio
• Evitar un torrente de cambios en cascada!
![Page 311: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/311.jpg)
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
![Page 312: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/312.jpg)
Open-Closed
var Canvas = Class.extend({ render: function(figura) { if (figura instanceof Triangulo) { // ... } else if (figura instanceof Cuadrado) { // ... } }});
![Page 313: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/313.jpg)
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) { ...}});
![Page 314: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/314.jpg)
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
![Page 315: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/315.jpg)
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!)!{
//!...}
![Page 316: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/316.jpg)
Open-Closed
Caso práctico: jasmine.js
•https://github.com/pivotal/jasmine/blob/master/src/core/Reporter.js
![Page 317: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/317.jpg)
Open-Closed
/**!No3op!base!class!for!Jasmine!reporters.!*!*!@constructor!*/jasmine.Reporter!=!function()!{};
//noinspection!JSUnusedLocalSymbolsjasmine.Reporter.prototype.reportRunnerStarting!=!function(runner)!{};
//noinspection!JSUnusedLocalSymbolsjasmine.Reporter.prototype.reportRunnerResults!=!function(runner)!{};
//...
![Page 318: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/318.jpg)
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
![Page 319: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/319.jpg)
Sustitución de Liskov
var Animal = Class.extend({ caminar: function() { /*...*/ }, comer: function() { /* .. */ }});
![Page 320: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/320.jpg)
Sustitución de Liskov
var Animal = Class.extend({ caminar: function() { /*...*/ }, comer: function() { /* ... */ }});
var Serpiente = Animal.extend({ /* ... */});
var s = new Serpiente();s.caminar();
![Page 321: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/321.jpg)
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”
![Page 322: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/322.jpg)
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
![Page 323: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/323.jpg)
Segregación de la intefaz
var Modal = Class.extend({ show: function() { ... }, hide: function() { ... }});
![Page 324: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/324.jpg)
Segregación de la intefaz
var Modal = Class.extend({ show: function() { ... }, hide: function() { ... }});
var Timer = Class.extend({ setTimer: function(time) { ... }, startTimer: function() { ... }, onTimeout: function() { ... }});
![Page 325: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/325.jpg)
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(); }});
![Page 326: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/326.jpg)
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(); }});
![Page 327: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/327.jpg)
Segregación de la intefaz
var WidgetView = Class.extend({ init: function(cont) { var cbind = curry(bind, cont); $("#E1").click(cbind(cont.onE1Click)); }});
![Page 328: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/328.jpg)
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)); }});
![Page 329: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/329.jpg)
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)); // ... }});
![Page 330: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/330.jpg)
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)); // ... }});
![Page 331: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/331.jpg)
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)); // ... }});
![Page 332: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/332.jpg)
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.
![Page 333: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/333.jpg)
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); }});
![Page 334: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/334.jpg)
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); }});
![Page 335: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/335.jpg)
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) { }});
![Page 336: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/336.jpg)
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(); }});
![Page 337: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/337.jpg)
Dependency Inversion
Caso práctico: backbone.js
• https://github.com/documentcloud/backbone/blob/master/backbone.js
• Backbone.Model#fetch, línea 335
![Page 338: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/338.jpg)
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);!!!!},
![Page 339: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/339.jpg)
Patrones de organización
![Page 340: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/340.jpg)
Patrones de organización
• Parámetros con nombre/por defecto
• Módulos y namespaces
• Control de acceso
• Mixins
![Page 341: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/341.jpg)
Parámetros con nombre
function ajax(url, data, method, success, error, complete) { url || url = "/"; data || data = {}; method || method = "POST"; // ...}
ajax("/", {}, "GET", function(){ ... }, function() { ... }, function() { ... });
![Page 342: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/342.jpg)
Parámetros con nombre
function ajax(options) { var url = options.url || "/", data = options.data || {}, method = options.method || "POST"; //...}
ajax({data: [1, 2], complete: function() { ... }});
![Page 343: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/343.jpg)
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() { ... }});
![Page 344: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/344.jpg)
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;!!!!},
![Page 345: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/345.jpg)
Intermedio: merge
¿Cómo sería esa función merge?
![Page 346: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/346.jpg)
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;}
![Page 347: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/347.jpg)
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
![Page 348: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/348.jpg)
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!
![Page 349: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/349.jpg)
Módulos y namespaces
function miHelper() { // ...}
var miVariableTemporal = 0;var estadoLocal = {};
![Page 350: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/350.jpg)
Módulos y namespaces
function sandbox() { function miHelper() { // ... }
var miVariableTemporal = 0; var estadoLocal = {}; }
![Page 351: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/351.jpg)
Módulos y namespaces
(function sandbox() { function miHelper() { // ... }
var miVariableTemporal = 0; var estadoLocal = {}; }())
![Page 352: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/352.jpg)
Módulos y namespaces
(function sandbox() { function miHelper() { // ... }
var miVariableTemporal = 0; var estadoLocal = {}; }())
![Page 353: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/353.jpg)
Módulos y namespaces
function miFuncionUtil() { // ...}
function miGranMetodo() { // ...}
function miEstupendoHelper() { // ...}
![Page 354: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/354.jpg)
Módulos y namespaces
function aux() { }var state = "off";
function miFuncionUtil() { // ...}
function miGranMetodo() { // ...}
function miEstupendoHelper() { // ...}
![Page 355: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/355.jpg)
Módulos y namespaces
(function() { function aux() { } var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { }
function miEstupendoHelper() { }}())
![Page 356: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/356.jpg)
Módulos y namespaces
var Modulo = (function() { function aux() { } var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { } return { miFuncionUtil: miFuncionUtil, miGranMetodo: miGranMetodo };}());
![Page 357: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/357.jpg)
Módulos y namespaces
var Modulo = (function() { function aux() { } var state = "off";
function miFuncionUtil() { }
function miGranMetodo() { } return { miFuncionUtil: miFuncionUtil, miGranMetodo: miGranMetodo };}());
![Page 358: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/358.jpg)
Módulos y namespaces
Modulo.miFuncionUtil();
![Page 359: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/359.jpg)
Módulos y namespaces
var Modulo = {};
(function(Modulo) { function aux() { } var state = "off";
Modulo.miFuncionUtil = function() { }
Modulo.miGranMetodo = function() { }
}(Modulo));
![Page 360: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/360.jpg)
Módulos y namespaces
var Modulo = {};
(function(Modulo) { function aux() { } var state = "off"; Modulo.miFuncionUtil = function() { }}(Modulo));
(function(Modulo) { Modulo.miGranMetodo = function() { }}(Modulo));
![Page 361: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/361.jpg)
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 || {}));
![Page 362: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/362.jpg)
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 || {}));
![Page 363: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/363.jpg)
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
![Page 364: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/364.jpg)
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
![Page 365: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/365.jpg)
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 || {}));
![Page 366: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/366.jpg)
Módulos y namespaces
var Modulo = (function (Modulo) { var _private = Modulo._private; // acceso a _private
}(Modulo || {}));
![Page 367: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/367.jpg)
Módulos y namespaces
Modulo._seal();
![Page 368: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/368.jpg)
Intermedio: mejorar klass.js
Convierte klass.js en un módulo Class
![Page 369: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/369.jpg)
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));
![Page 370: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/370.jpg)
Módulos y namespaces
Según crece la aplicación...
![Page 371: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/371.jpg)
Módulos y namespaces
Según crece la aplicación...
var MiLibreria = MiLibreria || {};
![Page 372: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/372.jpg)
Módulos y namespaces
Según crece la aplicación...
var MiLibreria = MiLibreria || {};MiLibreria.widgets = MiLibreria.widgets || {};
![Page 373: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/373.jpg)
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 || {}));
![Page 374: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/374.jpg)
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({ ... });});
![Page 375: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/375.jpg)
Intermedio: namespace
¿Como sería la función MiLib.namespace?
![Page 376: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/376.jpg)
Intermedio: namespace
¿Como sería la función MiLib.namespace?
var MiLib = (function(my) { my.namespace = function(string, sandbox) { // ??? }; return my;}(MiLib || {}));
![Page 377: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/377.jpg)
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 || {}));
![Page 378: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/378.jpg)
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
![Page 379: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/379.jpg)
Mixins
var Mixin = function() {};Mixin.prototype = { inspect: function() { var output = []; for(key in this) { output.push(key + ': ' + this[key]); } return output.join(', '); }};
![Page 380: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/380.jpg)
Mixins
var Persona = Class.extend({ init: function(nombre) { this.nombre = nombre; }});
augment(Persona, Mixin);
var pepito = new Persona("Pepito");pepito.inspect();
![Page 381: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/381.jpg)
Mixins
function augment(target, source) { for (var prop in source.prototype) { if(!target.prototype[prop]) { target.prototype[prop] = source.prototype[prop]; } }}
![Page 382: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/382.jpg)
Intermedio: Mejores Mixins
Lo podemos hacer mejor!
• Mejor integración con klass.js
• Callbacks de inclusión (estilo ruby)
![Page 383: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/383.jpg)
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);
![Page 384: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/384.jpg)
Patrones de creación de objetos
![Page 385: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/385.jpg)
Factoría
Delegar la creación de un objeto
• Elegir el constructor dinámicamente
• Procesos de construcción complejos
• Desacoplar detalles de implementación
![Page 386: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/386.jpg)
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 Title”
![Page 387: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/387.jpg)
Factoría
var GlobalConfig = {locale: "es"};
![Page 388: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/388.jpg)
Factoría
var GlobalConfig = {locale: "es"};
I18n.withCurrentLocale = function() { var instance = new this; instance.locale = GlobalConfig.locale; return instance;};
![Page 389: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/389.jpg)
Factoría
var i18n = I18n.withCurrentLocale();alert(i18n.translate('header.title'));
![Page 390: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/390.jpg)
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(); }};
![Page 391: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/391.jpg)
Factoría
Controlar las instanciasvar 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;}());
![Page 392: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/392.jpg)
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;}());
![Page 393: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/393.jpg)
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
![Page 394: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/394.jpg)
Singleton
Clase con una única instancia
• Un tipo peculiar de Factoría
• Cuando no tiene sentido más de una instancia
![Page 395: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/395.jpg)
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())
![Page 396: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/396.jpg)
Patrones de abstracción
![Page 397: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/397.jpg)
Patrones de abstracción
• Iteradores
• Decorador
• Fachada
• Estrategia
• Inyección de dependencias
• Proxy
![Page 398: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/398.jpg)
Iteradores
Recorrer una colección
• Sin revelar detalles de implementación
• Mayor control sobre la iteración
![Page 399: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/399.jpg)
Iteradores
var ListadoAlumnos = Class.extend({ init: function() { this.alumnos = []; }, add: function(nombre, ciudad) { this.alumnos.push({ nombre: nombre, ciudad: ciudad }); }});
![Page 400: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/400.jpg)
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");
![Page 401: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/401.jpg)
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); }}
![Page 402: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/402.jpg)
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); }}
![Page 403: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/403.jpg)
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); } }});
![Page 404: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/404.jpg)
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);});
![Page 405: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/405.jpg)
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++]; }});
![Page 406: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/406.jpg)
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);}
![Page 407: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/407.jpg)
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); }});
![Page 408: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/408.jpg)
Iteradores
var lista = new ListadoAlumnos();lista.add("Gonzalo", "Madrid");lista.add("Gerardo", "Madrid");lista.add("Guzman", "Valencia");
var alumno, iter = lista.getIterator();while(alumno = iter.next()) { if (alumno.ciudad == "Madrid") { console.log(alumno.nombre); }}
![Page 409: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/409.jpg)
Iteradores
var Fibonacci = Class.extend({ init: function() { this.a = 0; this.b = 1; }, next: function() { var next = this.a; this.a = this.b; this.b = this.b + next; return next; }});
var iter = new Fibonacci();for (var i=10; i--;) { console.log(iter.next());}
![Page 410: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/410.jpg)
Decorador
Añadir funcionalidad dinámicamente
• Evitar subclases innecesarias
• Modificar comportamientos “en vivo”
• Manteniendo la interfaz/contrato! (transparente)
• Muy apropiada para JS
![Page 411: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/411.jpg)
Decorador
var Producto = Class.extend({ init: function(precio) { this.precio = precio; }, getPrecio: function() { return this.precio; }});
![Page 412: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/412.jpg)
Decorador
var Producto = Class.extend({ init: function(precio) { this.precio = precio; }, getPrecio: function() { return this.precio; }});
var ProductoConIVA = Producto.extend({ init: function(precio) { this._super(precio); }, getPrecio: function() { return this._super() * 1.21; }});
![Page 413: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/413.jpg)
Decorador
var ProductoConDescuento = Producto.extend({ init: function(precio) { this._super(precio); }, getPrecio: function() { return this._super() * 0.90; }});
var ProductoConIVAConDescuento = ProductoConIVA.extend({ init: function(precio) { this._super(precio); }, getPrecio: function() { return this._super() * 0.90; }});
![Page 414: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/414.jpg)
Decorador
var ProductoTecnologico = Producto.extend({ });
var ProductoTecnologicoConDescuento = ProductoConDescuento.extend({});
var ProductoTecnologicoConIVA = ProductoConIVA.extend({});
var ProductoTecnologicoConIVAConDescuento = ProductoConIVAConDescuento.extend({});
![Page 415: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/415.jpg)
Decorador
var Producto = Class.extend({ init: function(precio) { this.precio = precio; }, getPrecio: function() { return this.precio; }});
![Page 416: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/416.jpg)
Decorador
var Producto = Class.extend({ init: function(precio) { this.precio = precio; }, getPrecio: function() { return this.precio; }});
var ProductoConIVA = Class.extend({ init: function(producto) { this.producto = producto; }, getPrecio: function() { return this.producto.getPrecio() * 1.21; }});
![Page 417: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/417.jpg)
Decorador
var ProductoConDescuento = Class.extend({ init: function(producto) { this.producto = producto; }, getPrecio: function() { return this.producto.getPrecio() * 0.90; }});
var ProductoTecnologico = Class.extend({ init: function(producto) { this.producto = producto; }, getPrecio: function() { return this.producto.getPrecio() * 0.90; }});
![Page 418: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/418.jpg)
Decorador
var producto = new Producto(20);producto = new ProductoConIVA(producto);producto = new ProductoConDescuento(producto);producto = new ProductoTecnologico(producto);producto.getPrecio(); // 19.602
![Page 419: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/419.jpg)
Decorador
var producto = new Producto(20);producto = new ProductoConIVA(producto);producto = new ProductoConDescuento(producto);producto = new ProductoTecnologico(producto);producto.getPrecio(); // 19.602
ProductoTecnológico
ProductoConDescuentoProductoConIVA
ProductogetPrecio()
getPrecio()
getPrecio()
getPrecio()
![Page 420: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/420.jpg)
Decorador
var producto = new Producto(20);producto = new ProductoConIVA(producto);producto = new ProductoConDescuento(producto);producto = new ProductoTecnologico(producto);producto.getPrecio(); // 19.602
ProductoTecnológico
ProductoConDescuentoProductoConIVA
Producto
(20 * 1.21) * 0.90
20 * 1.21
20
((20 * 1.21) * 0.90) * 0.90
19.602
![Page 421: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/421.jpg)
Decorador
Cuando usar decoradores:
• Modificar el comportamiento manteniendo interfaz
• Añadir post- o preproceso a la salida/entrada de un obj
- Serialización
- Interfaz
• Dentro de factorías
• Intervenir el llamadas a métodos
![Page 422: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/422.jpg)
Fachada
Simplificar el interfaz y desacoplar al cliente
• Patrón muy simple
• El mejor amigo del programador JavaScript
• Casi todas las librerías son fachadas
• Comodidad
![Page 423: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/423.jpg)
Fachada
Ejemplo por excelencia: jQuery
• $(“selector”)• $(“selector”).click(...)• $.ajax• ...
![Page 424: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/424.jpg)
Fachada
Nuestra librería klass.js
• Una capa sobre los mecanismos nativos
• Simplifica el “interfaz”
• Mucho más cómodo que hacerlo a mano
![Page 425: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/425.jpg)
Fachada
var DOMNode = Class.extend({ init: function(tag) { this.el = document.createElement(tag); }, setClass: function(klass) { this.el.className += (" " + klass); }, setId: function(id) { this.el.id = id; }, getElement: function() { return this.el; }});
var node = new DOMNode('div');node.setClass("big");node.setClass("red");node.setId("my-button");document.body.appendChild(node.getElement());
![Page 426: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/426.jpg)
Fachada
DOMNode.create = function(tag, classes, id) { var node = new this(tag); node.setClass(classes.join(" ")); node.setId(id); return node.getElement();}var el = DOMNode.create("div", ["big", "red"], "my-button");document.body.appendChild(el);
![Page 427: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/427.jpg)
Fachada
¿Cuándo usar fachadas?
• Clases muy potentes y complejas
- Simplificar los usos más comunes
• Operaciones con mucha preparación
- XMLHttpRequest
• Código repetitivo
• Para cambios grandes del código
![Page 428: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/428.jpg)
Estrategia
Seleccionar algoritmos dinámicamente
• Dada una familia de algoritmos
• Encapsulados bajo un mismo interfaz
• Elegir el más apropiado
![Page 429: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/429.jpg)
Estrategia
var validate = (function() { var validators = { email: function(value) { return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value); }, number: function(value) { return /^\d+$/.test(value); } }; return function(data) { var validation = validators[data.type]; return validation && validation(data.value); };}());
validate({type: "email", value: "[email protected]"});
![Page 430: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/430.jpg)
Estrategia
var MoodConsole = Class.extend({ init: function() { this.state = "normal"; this.filters = { normal: new DummyFilter(), relajado: new RelaxedFilter(), cabreado: new AngryFilter() }; }, log: function(msg) { msg = this.filters[this.state].filter(msg); console.log(msg); }, molestar: function() { this.state = "cabreado"; }, masajear: function() { this.state = "relajado"; }, dejarEnPaz: function() { this.state = "normal"; }});
![Page 431: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/431.jpg)
Estrategia
var DummyFilter = Class.extend({ filter: function(s) { return s; }});
var AngryFilter = DummyFilter.extend({ filter: function(s) { return s.toUpperCase() + "!!"; }});
var RelaxedFilter = DummyFilter.extend({ filter: function(s) { return "..." + s + "..."; }});
var moodConsole = new MoodConsole();moodConsole.log("hola!");moodConsole.molestar();moodConsole.log("grrr...");moodConsole.masajear();moodConsole.log("gracias");
![Page 432: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/432.jpg)
Estrategia
¿Cuándo usar estrategias?
• Una misma acción puede tener varios significados
- Según un estado variable (selector de contexto)
- click, touch, una botón “Guardar”, etc..
• Validaciones
• En general: cuando hay que elegir un algoritmo diferente para cada caso
![Page 433: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/433.jpg)
Inyección de dependencias
Selección dinámica de un componente
• Según el principio de Inversión de Dependencias
• El cliente consume siguiendo un interfaz
• La clase concreta se selecciona en tiempo de ejecución
![Page 434: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/434.jpg)
Inyección de dependencias
var View = Class.extend({ init: function(renderer, model) { this.renderer = renderer; this.model = model; }, render: function() { this.renderer.render(this.template, this.model); }});
var HtmlRenderer = Class.extend({ render: function() { ... }});
var XMLRenderer = Class.extend({ render: function() { ... }});
![Page 435: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/435.jpg)
Inyección de dependencias
var miVista = new View(new XMLRenderer('fast'), {});
![Page 436: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/436.jpg)
Proxy
Un objeto hace de interfaz de otro objeto o recurso
• Entre el cliente y el servicio
• Controlar y optimizar el acceso
• El Proxy implementa exactamente el mismo interfaz
- No es un decorador (no añade funcionalidad)
- No es una fachada (no simplifica)
![Page 437: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/437.jpg)
Proxy
Tres tipos de proxy:
• Virtual Proxy
- Sustituye al objeto real mientras carga
- Optimización
• Protection Proxy
- Controla el acceso
- Seguridad
• Remote Proxy
- Reflejo de un recurso remoto
- Abstracción
![Page 438: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/438.jpg)
Virtual Proxy
var Recurso = Class.extend({ init: function() { operacionMuyCostosa(); }, read: function() { ... }, write: function() { ... }});
![Page 439: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/439.jpg)
Virtual Proxy
var Recurso = Class.extend({ init: function() { operacionMuyCostosa(); }, read: function() { ... }, write: function() { ... }});
var RecursoProxy = Recurso.extend({ init: function() { this.super_init = this._super; }, read: function() { this.super_init(); this._super(); }, write: function() { this.super_init(); this._super(); }});
![Page 440: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/440.jpg)
Virtual Proxy
var Recurso = Class.extend({ init: function() { operacionMuyCostosa(); if (this.onLoad) this.onLoad(); }, write: function() { ... }});
var RecursoProxy = Recurso.extend({ init: function() { this.pending = []; this.loaded = false; this._super(); }, write: function() { if (loaded) { this._super(); } else { pending.push({op: 'write', params: arguments}); } }});
![Page 441: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/441.jpg)
Remote Proxy
var User = Class.extend({ init: function() { /*...*/ }, getName: function() { return this.name; }});
User.find = function(id, cb) { $.get('/user/' + id, function(data) { var user = new User(data); cb(user); });};
User.find(12, function(user) { console.log(user.getName());});
![Page 442: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/442.jpg)
Proxy
¿Cuándo usar un Proxy?
• Inicialización perezosa
• “Sustituto” que anote mientras el sujeto real arranca
• Cuando el sujeto real es remoto
• Cache!
![Page 443: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/443.jpg)
Patrones de interacción
![Page 444: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/444.jpg)
Patrones de interacción
• Pub/Sub u Observador
• Mediator
• Comandos y Cadena de Responsabilidad
• “Hydra”
![Page 445: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/445.jpg)
Observador
En vez de preguntar, escucha lo que sucede
• Muy común en JavaScript (eventos)
• Reaccionar ante cambios de estado o sucesos
• Dos entidades
- Publicador
- Suscriptor(es)
![Page 446: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/446.jpg)
Observador
var Input = Class.extend({ getValue: function() { return this.value; }});
var InputView = Class.extend({ init: function(input) { this.input = input; this.value = this.input.getValue(); setInterval(bind(this, this.onTimer), 100); }, onTimer: function() { var newValue = this.input.getValue(); if (newValue !== this.value) { this.value = newValue; console.log("CHANGED: " + this.value); } }});
![Page 447: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/447.jpg)
Observador
InputInputViewcambios?
no..
InputInputViewcambios?
no..
InputInputViewcambios?
no..
InputInputViewcambios?
no..
0ms
100ms
200ms
300ms
![Page 448: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/448.jpg)
Observador
InputInputViewavísame!
InputInputViewcambios!
0ms
T ms
![Page 449: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/449.jpg)
Observador
var Input = Class.extend({ init: function() { this.observers = []; }, getValue: function() { return this.value; }, setValue: function(v) { this.value = v; this.publish(v); }, onChange: function(cb) { this.observers.push(cb); }, publish: function(cb) { this.observers.forEach(function(o) { o(cb); }); }});
![Page 450: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/450.jpg)
Observador
var Input = Class.extend({ init: function() { this.observers = []; }, getValue: function() { return this.value; }, setValue: function(v) { this.value = v; this.publish(v); }, onChange: function(cb) { this.observers.push(cb); }, publish: function(cb) { this.observers.forEach(function(o) { o(cb); }); }});
![Page 451: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/451.jpg)
Observador
var InputView = Class.extend({ init: function(input) { this.input = input; this.input.onChange(bind(this, this.update)); }, update: function(newValue) { console.log("CHANGED: " + newValue); }});
![Page 452: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/452.jpg)
Observador
var input = new Input();
var observer1 = new InputView(input);var observer2 = new InputView(input);var observer3 = new InputView(input);
input.setValue("No te duermas!");
![Page 453: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/453.jpg)
Intermedio: Observable
¡Podemos hacerlo mejor!
Input.mixin(Observable);
var InputView = Class.extend({ init: function(input) { this.input.subscribe('change', bind(this, this.update)); this.input.subscribe('invalid', bind(this, this.invalid)); }, update: function(newValue) { console.log("CHANGED: " + newValue); }, invalid: function(value) { console.log("El valor " + value + " es inválido!" ); }});
![Page 454: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/454.jpg)
Intermedio: Observable
var Observable = { mixed: function(klass) { // ??? }, subscribe: function(event, callback) { // ??? }, unsubscribe: function(event, callback) { // ??? }, publish: function(event) { // ??? }};
![Page 455: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/455.jpg)
Observador
¿Cuándo utilizar Observador?
• Se utiliza muy a menudo!
• Propagar cambios
• Reaccionar a sucesos
• Comunicación uno-a-muchos
![Page 456: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/456.jpg)
Mediator
Un punto central de control del sistema
• Desacoplamiento a gran escala
• Sencillo y muy importante
• Dividir la lógica en dos niveles
- Componente
- Aplicación
![Page 457: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/457.jpg)
Mediator
![Page 458: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/458.jpg)
Mediator
x
![Page 459: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/459.jpg)
Mediator
x
Aceptar
![Page 460: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/460.jpg)
Mediator
x
Aceptar
![Page 461: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/461.jpg)
Mediator
componente
componente
componente
componente
componente
![Page 462: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/462.jpg)
Mediator
componente
componente componente
componente componente
mediador
![Page 463: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/463.jpg)
Mediator
componente
componente componente
componente componente
mediador
![Page 464: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/464.jpg)
Mediator
var Mediator = Class.extend({ init: function(fn) { this.connections = {}; if (fn) fn(this); }, on: function(msg, cb) { this.connections[msg] = cb; }, send: function(msg) { var args = [].slice.call(arguments, 1), action = this.connections[msg]; if (action) action.apply({}, args); }, addComponent: function(component) { component.setMediator(this); }});
![Page 465: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/465.jpg)
Intermedio: Mediator
• Mediador en acción:
- tema2/mediador-1/index.html
![Page 466: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/466.jpg)
Intermedio: Mediator
// Inicialización
$(function() {
var mediator = new Mediator(), button1 = new Button('pulsador', '#button-1'); mediator.addComponent(button1); mediator.on('pulsador:clicked', function() { alert("hola?"); }); });
![Page 467: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/467.jpg)
Intermedio: Mediator
// Inicialización
$(function() {
var mediator = new Mediator(function(mediator) { var button1 = new Button('pulsador', '#button-1'); mediator.addComponent(button1); mediator.on('pulsador:clicked', function() { alert("hola?"); }); }); });
![Page 468: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/468.jpg)
Intermedio: Mediator
• Mediador en acción:
- tema2/mediador-2/index.html
![Page 469: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/469.jpg)
Intermedio: Mediator
mediator.on('ignore:on', function() { enabled = false;});
mediator.on('ignore:off', function() { enabled = true;});
mediator.on('inc:clicked', function() { if (enabled) { count.increment(); } display.update(count.getCurrentValue());});
mediator.on('dec:clicked', function() { if (enabled) { count.decrement(); } display.update(count.getCurrentValue());});
![Page 470: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/470.jpg)
Intermedio: Mediator
mediator.on('ignore:on', function() { enabled = false;});
mediator.on('ignore:off', function() { enabled = true;});
mediator.on('inc:clicked', function() { if (enabled) { count.increment(); } display.update(count.getCurrentValue());});
mediator.on('dec:clicked', function() { if (enabled) { count.decrement(); } display.update(count.getCurrentValue());});
![Page 471: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/471.jpg)
Mediator
¿Cuándo usar un Mediador?
• Muchos componentes interactuando
• La interacción se puede separar del componente
• Es decir: coordinar diferentes widgets de la aplicación
![Page 472: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/472.jpg)
Mediator
¿Cuándo usar un Mediador?
• Muchos componentes interactuando
• La interacción se puede separar del componente
• Es decir: coordinar diferentes widgets de la aplicación
¡Cuidado!
๏ El mediador tiende a convertirse en un cajón de sastre
๏ Una Gran Función que Todo lo Hace!
![Page 473: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/473.jpg)
Comandos
Separar la preparación de una acción y su ejecución
• Flujos de ejecución no convencionales
• Tres actores: cliente, invocador, receptor
- cliente: prepara o configura una acción
- invocador: controla la ejecución
- receptor: lleva a cabo la acción
• Generalizar comportamientos
![Page 474: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/474.jpg)
Comandos
tema2/comandos-1/index.html
![Page 475: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/475.jpg)
Comandos
var Command = Class.extend({ init: function(msg) { this.msg = msg; }, execute: function() { alert(this.msg); }});
var ActionList = Class.extend({ init: function(selector) { this.ul = $(selector); }, append: function(name, command) { var li = $("<li>") .append($('<a/>', {html:name, href:'#'})) .click(bind(command, command.execute)) .appendTo(this.ul); }});
var list = new ActionList('#menu');list.append('saludo', new Command("Hola!"));list.append('achis!', new Command("Salud!"));
![Page 476: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/476.jpg)
Comandos
var Command = Class.extend({ init: function(msg) { this.msg = msg; }, execute: function() { alert(this.msg); }});
var ActionList = Class.extend({ init: function(selector) { this.ul = $(selector); }, append: function(name, command) { var li = $("<li>") .append($('<a/>', {html:name, href:'#'})) .click(bind(command, command.execute)) .appendTo(this.ul); }});
var list = new ActionList('#menu');list.append('saludo', new Command("Hola!"));list.append('achis!', new Command("Salud!"));
![Page 477: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/477.jpg)
Comandos
var AlertCommand = Class.extend({ init: function(msg) { this.msg = msg; }, execute: function() { alert(this.msg); }});
var LogCommand = Class.extend({ init: function(msg) { this.msg = msg; }, execute: function() { console.log(this.msg); }});
![Page 478: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/478.jpg)
Comandos
Encapsular las acciones y controlar su ejecución
• Una idea muy potente
• Deshacer! (estados reversibles)
• Historial
• Control de cambios
• Sincronización de estados
![Page 479: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/479.jpg)
Comandos
Un ejemplo sencillo de estado reversible:
• tema2/comandos-2/index.html
var Movement = Class.extend({ init: function(amount, axis) { this.amount = amount; this.axis = axis; }, execute: function(mosca) { mosca.move(this.amount, this.axis); }, undo: function(mosca) { mosca.move(-this.amount, this.axis); }});
![Page 480: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/480.jpg)
Comandos
¿Cuándo usar Comandos?
• Controlar la ejecución de acciones
• Separar la definición de la acción y su ejecución
• Es decir:
- Intervienen actores que pueden fallar (servidor, usuario)
- Menús, selectores y otros “contenedores de acciones”
- Sincronizar cambios simultáneos (control de versiones)
![Page 481: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/481.jpg)
Cadena de Responsabilidad
Cada eslabón decide actuar o delegar en el próximo
• Elegir dinámicamente quien responde a una petición
• Dividir una operación compleja en varios pasos
• Desacoplar la complejidad del cliente
![Page 482: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/482.jpg)
Cadena de Responsabilidad
var AlmacenVehiculos = Class.extend({ init: function(tipo) { this.tipo = tipo; this.vehiculos = []; }, guardar: function(vehiculo) { if (vehiculo.getTipo() == this.tipo) { this.vehiculos.push(vehiculo); } }});
var hangar = new AlmacenVehiculos('avion'), parking = new AlmacenVehiculos('coche'), puerto = new AlmacenVehiculos('barco');
![Page 483: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/483.jpg)
Cadena de Responsabilidad
var Vehiculo = Class.extend({ init: function(tipo) { this.tipo = tipo; }, getTipo: function() { return this.tipo; }, guardar: function() { hangar.guardar(this); puerto.guardar(this); parking.guardar(this); }});
![Page 484: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/484.jpg)
Cadena de Responsabilidad
var AlmacenVehiculos = Class.extend({ init: function(tipo, siguiente) { this.tipo = tipo; this.vehiculos = []; this.siguiente = siguiente; }, guardar: function(vehiculo) { if (vehiculo.getTipo() == this.tipo) { this.vehiculos.push(vehiculo); } else if (siguiente.next) { this.siguiente.guardar(vehiculo); } }});
![Page 485: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/485.jpg)
Cadena de Responsabilidad
var hangar = new AlmacenVehiculos('avion'), parking = new AlmacenVehiculos('coche', hangar), puerto = new AlmacenVehiculos('barco', parking), almacenes = new AlmacenVehiculos('', puerto);
var Vehiculo = Class.extend({ init: function(tipo) { this.tipo = tipo; }, getTipo: function() { return this.tipo; }, guardar: function() { almacenes.guardar(this); }});
![Page 486: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/486.jpg)
Cadena de Responsabilidad
¿Cuándo usar Cadenas de Reponsabilidad?
• Jerarquías de objetos
- Los eventos del navegador
• Diferentes fuentes para responder a una petición
- Ej: buscar por nombre, por fecha, por ciudad, ...
• El input puede afectar a varias entidades
- Ej: Colisiones
![Page 487: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/487.jpg)
Hydra
Árbol de comportamientos
• No existe
• Organización al más alto nivel
• Mediador + Comandos + Cadena de Responsabilidad
• Extremadamente escalable!
• Para aplicaciones muy grandes
![Page 488: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/488.jpg)
Hydra
Librería DOM
Componente
Mediador Global
Componente Componente
![Page 489: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/489.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Componente
Componente
Mediador Local
Componente
Componente
Componente
Mediador Local
Componente
Componente
Componente
![Page 490: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/490.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
![Page 491: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/491.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
click en “Guardar”
![Page 492: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/492.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
click en “Guardar”
Dame los datosdel formulario
Componente
![Page 493: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/493.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
click en “Guardar”
Guardar nuevosdatos de usuario
![Page 494: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/494.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
click en “Guardar”
Guardar nuevosdatos de usuario
Actualiza lalista decontactos
Mediador Local
![Page 495: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/495.jpg)
Hydra
Librería DOM
Mediador Global
Mediador Local
Componente
Ajax + DOM
Coordinación general
Coordinación local
Lógica del componente
click en “Guardar”
Guardar nuevosdatos de usuario
Haz un POSTa /users
![Page 496: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/496.jpg)
Hydra
Separación por capas de significado
• Cada mediador gestiona lo que hay a su nivel
• El significado de las acciones va cobrando sentido
• La lógica de los componentes se limita a hablar con su mediador
• La coordinación es “recursiva”
![Page 497: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/497.jpg)
Hydra
¿Cuándo utilizar Hydra?
• Aplicaciones grandes!
• Widgets complicados que se beneficien de mediación
• En general, en cuanto un mediador engorde demasiado
![Page 498: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/498.jpg)
Hydra
¿Cuándo utilizar Hydra?
• Aplicaciones grandes!
• Widgets complicados que se beneficien de mediación
• En general, en cuanto un mediador engorde demasiado
¡Cuidado!
๏ El alto desacoplamiento hace complicado leer el código
๏ El significado TOTAL de cada acción está diseminado
![Page 499: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/499.jpg)
MVC: Backbone.js
made with love by Redradix (www.redradix.com)
![Page 500: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/500.jpg)
El problema: acoplamiento
Las aplicaciones JS tienden a ser un caos
• La lógica del interfaz se mezcla con
• La lógica de control y validación de datos y con
• La lógica de comunicación con el servidor y con
• La lógica de reacción a eventos!
![Page 501: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/501.jpg)
El problema: acoplamiento
El peor tipo de código espagueti!
$.ajax({ url: 'events/since', data: { timestamp: old_id }, dataType: 'json', type: 'GET', global: false, cache: false, success: function(newEvents) { if (newEvents.events && newEvents.events.length != 0) { if (prepend_events) { if (page <= '1') { if ($('div.new_events').length == 0) { $('#events').prepend('<div class="note new_events"><strong class="new_event_count">'+newEvents.events.length+'</strong> New Events Are Available Click here To View Them.</div>');
![Page 502: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/502.jpg)
MVC
En los 70 se propuso una solución:
• Separar el código en 3 componentes:
- Modelo: datos y lógica de negocio
- Vista: presentación de los datos
- Controlador: gestión de interacciones
• Limitar su comunicación
• Muy popular desde hace mucho tiempo!
- Aplicaciones de escritorio
- Aplicaciones móviles
- Una interpretación peculiar en los frameworks web
![Page 503: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/503.jpg)
MVC
Se ha extendido hace “poco” por JS
• Backbone.js
• Spine.js
• Batman.js
• Ember.js
• ...
![Page 504: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/504.jpg)
MVC
M
V C
Usuario
Ve Usa
ManipulaActualiza
![Page 505: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/505.jpg)
MVC
Vamos a aplicar el patrón MVC
• Entender su filosofía
• Comprender los mecanismos fundamentales
• Apreciar sus ventajas
• Ver sus limitaciones
• Estudiar diferentes soluciones
![Page 506: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/506.jpg)
MVC
JS con todas nuestras utilidades:
• tema4/lib/prelude.js
- Class con herencia de propiedades de clase
- bind, curry, clone, merge
- Namespaces
- Observable
- Algunas utilidades extra
![Page 507: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/507.jpg)
Modelo
![Page 508: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/508.jpg)
Modelo
El Modelo se encarga de manejar los datos
• Representa una entidad
• Mecanismos de lectura y modificación
• Operaciones con los datos
• Validación
• Serialización
![Page 509: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/509.jpg)
Modelo
Representar una entidad
var Usuario = Backbone.Model.extend({ /* ... */})
![Page 510: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/510.jpg)
Modelo
Un modelo, en esencia, un conjunto de atributos
var u = new Usuario();
/* Crear o modificar un atributo */u.set({nombre: "Pepito"});
/* Leer el valor de un atributo */var nombre = u.get("nombre");console.log(nombre);
![Page 511: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/511.jpg)
Modelo
Valores por defecto para los atributos: defaults
var Usuario = Backbone.Model.extend({ defaults: { nombre: "Anónimo", nacionalidad: "Español" }});
var u = new Usuario();console.log(u.get("nombre"));
u.set({nombre: "Pepito"});console.log(u.get("nombre"));
![Page 512: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/512.jpg)
Modelo
Un modelo es un objeto, ¡Pero ten cuidado!
var Usuario = Backbone.Model.extend({ defaults: { nombre: "Anónimo", nacionalidad: "Español" }, saludar: function() { return "Hola, soy " + this.nombre; }});
var u = new Usuario();u.set({nombre: "Pepito"});console.log(u.saludar()); // "Hola, soy undefined"
![Page 513: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/513.jpg)
Modelo
Los atributos del modelo se consultan con get/set
var Usuario = Backbone.Model.extend({ defaults: { nombre: "Anónimo", nacionalidad: "Español" }, saludar: function() { return "Hola, soy " + this.get("nombre"); }});
var u = new Usuario();u.set({nombre: "Pepito"});console.log(u.saludar()); // "Hola, soy Pepito"
![Page 514: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/514.jpg)
Modelo
Serializar los atributos: .toJSON()
var Usuario = Backbone.Model.extend({ defaults: { nombre: "Anónimo", nacionalidad: "Español" }, saludar: function() { return "Hola, soy " + this.get("nombre"); }});
var u = new Usuario();u.set({nombre: "Pepito"});
var attrs = u.toJSON();console.log(attrs);
![Page 515: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/515.jpg)
Modelo
Validez: método .validate(attrs)• El método no viene definido por defecto
• Nosotros lo creamos para validar nuestro modelo
• Se llama automáticamente desde save
• Se puede forzar al hacer .set()
![Page 516: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/516.jpg)
Modelo
Validez: método .validate(attrs)• Si los valores de attrs no son válidos:
- Devuelve una descripción del error
- Puede ser cualquier cosa...
• Si son válidos:
- No se devuelve nada
![Page 517: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/517.jpg)
Modelo
var Usuario = Backbone.Model.extend({ defaults: { nombre: "Anónimo", nacionalidad: "Español" }, validate: function (attrs) { if (/^\s*$/.test(attrs["nombre"])) { return "El nombre no puede quedar en blanco!"; } }});
var u = new Usuario();
u.set({nombre: "Pepito"}, {validate: true});console.log(u.get("nombre"));
u.set({nombre: " "}, {validate: true});console.log(u.get("nombre")); // "Pepito"
![Page 518: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/518.jpg)
Modelo
Backbone.js es una librería agnóstica en muchos sentidos
• No impone templates
• No impone estructura
• No impone almacenamiento
![Page 519: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/519.jpg)
Modelo
Backbone.js es una librería agnóstica en muchos sentidos
• No impone templates
• No impone estructura
• No impone almacenamiento
Excepto...
• Impone su propio sistema de herencia y clases
• Muy simple
• Muy limitado
![Page 520: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/520.jpg)
Modelo
var Usuario = Backbone.Model.extend({ initialize: function () { // Constructor }});
var Ninja = Usuario.extend({ initialize: function () { Usuario.prototype.initialize.apply(this, arguments); // Subclase }});
![Page 521: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/521.jpg)
Modelo
Parecida a la nuestra, pero:
• No se pueden crear objetos que no hereden de una clase base de Backbone (Model, View, Collection o Router)
• La manera de llamar al súper método es incómoda y viola el principio DRY
![Page 522: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/522.jpg)
Modelo
Por suerte...
• Javascript es tremendamente flexible
• El modelo de Backbone es muy simple
• klass.js la hemos escrito nosotros y entendemos cómo funciona
![Page 523: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/523.jpg)
Modelo
Podemos integrar ambas librerías fácilmente!
• “Envolviendo” las clases base de Backbone en clases de klass.js
• Así tenemos lo mejor de las dos
![Page 524: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/524.jpg)
klass.js <-> backbone.js
var ProJS = (function (my) { var wrapBackboneClass = function(className) { var backboneWrapped = Backbone[className], F = function() {}, K = function() {}; F.prototype = backboneWrapped.prototype; K.prototype = new F(); _.extend(K, ProJS.Class, {constructor: backboneWrapped}); _.extend(K.prototype, ProJS.Class.prototype); K.prototype.init = function() { return backboneWrapped.apply(this, arguments); }; return K; };
my.Model = wrapBackboneClass('Model'); my.View = wrapBackboneClass('View'); my.Collection = wrapBackboneClass('Collection');
return my;}(ProJS || {}));
![Page 525: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/525.jpg)
klass.js <-> backbone.js
Ahora podemos hacer:
var Usuario = ProJS.Model.extend({ init: function() { // constructor this._super(); }, defaults: { // etc... }});
![Page 526: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/526.jpg)
Modelo
Ejercicio (uno fácil para empezar):
tema4/model-1/index.html
• Escribe un modelo Producto
- Id (incremento automático)
- Nombre (obligatorio)
- Categoría (obligatorio)
- País (España, Portugal o Francia)
- Precio (obligatorio, sin IVA)
• Escribe un decorador para obtener precios con IVA
![Page 527: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/527.jpg)
Modelo
Fíjate en...
• Lo fácil que resulta sobreescribir la funcionalidad de un método con klass.js
• Si no tuviéramos klass.js, ¿Cómo habríamos hecho el decorador? ¿De quién tendría que haber heredado?
• Puedes pasar varios atributos a la vez a .set()
• Puedes pasar los atributos directamente al constructor
• Es una base bastante sólida para controlar los datos de nuestra aplicación!
![Page 528: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/528.jpg)
Modelo
Los modelos generan eventos
• Cuando alguno de sus atributos cambia: change
• Cuando un atributo en concreto cambia: change:[attr]
• Cuando las validaciones fallan: invalid
• Al ser destruidos: destroy
• Al ser sincronizado con el servidor: sync
• Si surge algún error al guardar: error
![Page 529: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/529.jpg)
Modelo
var p1 = new Producto();
p1.on("change", function (model, options) { console.log("El producto", model.get("nombre"), "ha cambiado!");});
p1.set({ nombre: "Jamón", categoria: "Comida", pais: "España", precio: 65});
![Page 530: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/530.jpg)
Modelo
Ejercicio:
• Modifica el ejercicio anterior de modo que:
• Cuando una validación falla, se informe al usuario del error por la consola
![Page 531: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/531.jpg)
Modelo
Otras operaciones útiles:
.unset(): elimina un atributo
.clear(): elimina todos los atributos
.previous(attr): durante un evento change, devuelve el valor anterior de un atributo
.has(attr): ¿Tiene el modelo el atributo attr?
.escape(attr): como .get(), pero escapando el HTML
![Page 532: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/532.jpg)
Modelo
Persistencia
• La “gracia” de Backbone es que sabe como hablar con el servidor
• Pedir y guardar modelos automáticamente por AJAX
• Muy flexible
• Soporta también localStorage
![Page 533: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/533.jpg)
Modelo
Para hablar con el servidor, el modelo necesita:
• urlRoot: la base con la que construir su URL
• id: el identificador del recurso
• parse (opcional): una función que interprete la respuesta del servidor
![Page 534: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/534.jpg)
Modelo
Las operaciones fundamentales de persistencia:
.fetch()1. dado un id, construye una url del tipo [baseURL]/[id]
2. GET al servidor
3. pasa la respuesta a .parse()4. con el resultado llama a .set() para establecer los atributos
del modelo
![Page 535: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/535.jpg)
Modelo
Ejercicio
tema4/model-2/index.html
Con una api AJAX tal que:
GET /products -> lista de {nombre: “”, id: #}
GET /products/:id -> detalles del producto :id
PUT /products/:id -> guarda cambios del producto :id
Haz:
- Construye un array con un modelo por cada producto del listado
- Modifica algún producto y guarda los cambios
- Escucha los eventos “change”y “sync” e informa por consola
![Page 536: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/536.jpg)
Colecciones
Colección: conjunto ordenado de modelos
• Se identifica con un listado de recursos
- GET a URLs de tipo “índice” (/users, /products, etc...)
• Los modelos de una colección son del mismo tipo
![Page 537: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/537.jpg)
Colecciones
• Objetivo similar al del un modelo, pero con conjuntos
- Manejar colecciones de datos
- Ordenar, añadir, eliminar entidades a la colección
- Consultar y guardar la colección en el servidor
- Serializar el conjunto de datos
![Page 538: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/538.jpg)
Colecciones
var ListadoProductos = ProJS.Collection.extend({ model: Producto});
var listado = new ListadoProductos();
![Page 539: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/539.jpg)
Colecciones
Operaciones fundamentales:
- add(model, {at: i}): añadir un modelo a la colección
- remove(model|id|cid): eleminar un modelo
- get(id|cid): acceder a un objeto de la colección por id
- at(idx): acceder a un objeto de la colección por índice
- length: número de elementos en la colección
- where(attrs): query de atributos
- push/pop, shift/unshift
![Page 540: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/540.jpg)
Colecciones
var listado = new ListadoProductos();
listado.add(new Producto({nombre: "Uno"}));listado.add(new Producto({nombre: "Dos"}));listado.add(new Producto({nombre: "Tres"}));
console.log(listado.at(2).toJSON());
![Page 541: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/541.jpg)
Colecciones
Para identificar a los modelos dentro de una colección, podemos usar:
• id- Generalmente otorgado por el servidor
- Se utiliza para construir la URL del modelo
- Universal dentro de la app
- Se corresponde, habitualmente, con el ID de la tabla en BBDD
• cid- Generado automáticamente por Backbone
- Válido solo dentro de la página
- Modelos no guardados o que no tienen que ver con BBDD
![Page 542: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/542.jpg)
Colecciones
console.log(new Producto().cid); // c1console.log(new Producto().cid); // c2console.log(new Producto().cid); // c3
![Page 543: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/543.jpg)
Colecciones
var p = new Producto({nombre: "Zapatos"}), cid = p.cid;
console.log(listado.get(cid)); // undefined
listado.add(p);console.log(listado.get(cid)); // p
var resultado = listado.where({nombre: "Zapatos"});console.log(resultado.toJSON()); // p
![Page 544: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/544.jpg)
Colecciones
Una colección sabe como interpretar datos “crudos” (instancia automáticamente un modelo)
listado.add({ nombre: "Corbata", categoría: "Caballero", precio: 40});
listado.at(0).constructor === Producto; // true
![Page 545: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/545.jpg)
Colecciones
Cargar datos iniciales en una colección: reset
var listado = new ListadoProductos();
listado.reset([ {nombre: "Uno", categoria: "A", precio: 2}, {nombre: "Dos", categoria: "B", precio: 1}, {nombre: "Tres", categoria: "C", precio: 8},]);
![Page 546: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/546.jpg)
Colecciones
Las 28 funciones de underscore para manipular listas se pueden aplicar a colecciones
mapreducefindfiltermax/minsortshuffleetc...
![Page 547: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/547.jpg)
Colecciones
Persistencia:
url: dirección para pedir la colección
- Los modelos de la colección usarán esta URL como urlRoot para construir sus URLs individuales
fetch: pide la colección al servidor
- GET a url, esperando un array de hashes (atributos)
set: refresca los datos de la colección
- Aproximadamente igual que hacer un fetch y mergear
![Page 548: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/548.jpg)
Colecciones
Ejercicio:
tema4/collection-1/index.html
Crea una colección de Productos que lea de /products
Y tenga los métodos:
listado(): todos los productos
ordenaPorNombre(): filtro
precioMenorQue(p): filtro
borrarProducto(id): lo elimina de la BBDD
nuevoProducto(attrs): añade el producto a la colección y lo guarda en BBDD
![Page 549: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/549.jpg)
Colecciones
Las colecciones también emiten eventos:
add(model, col): se ha añadido un nuevo modelo
remove(model, col): se ha eliminado un modelo
sort(col): se ha reordenado
![Page 550: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/550.jpg)
Vista
Es una representación del modelo
• Asociada a una instancia de un modelo
• Generalmente utiliza un template
• Actualización automática
![Page 551: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/551.jpg)
Vista
Templates
• “Plantillas” que mezclan HTML y código JS
• Backbone funciona con cualquier librería de templates
• Trae una preinstalada: _.template()
![Page 552: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/552.jpg)
Vista
_.template(texto, datos)• texto: el texto de nuestra plantilla
• datos: un objeto con las variables que queramos utilizar al evaluar el template
![Page 553: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/553.jpg)
Vista
En el texto de la plantilla:
<%= expresión %>Se sustituye por el resultado de evaluar la expresión
<% código %>Ejecuta el código javascript
![Page 554: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/554.jpg)
Vista
var plantilla = "<h1> Hola! </h1>";console.log( _.template(plantilla, {}));
![Page 555: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/555.jpg)
Vista
var plantilla = " <h1> \ <% console.log('Hola!') %> \ </h1>";
console.log( _.template(plantilla, {}));
![Page 556: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/556.jpg)
Vista
var plantilla = " <h1> \ <%= 10 + 10 %> \ </h1>";
console.log( _.template(plantilla, {}));
![Page 557: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/557.jpg)
Vista
var plantilla = " <h1> \ Bienvenido, <%= nombre %> \ </h1>";
console.log( _.template(plantilla, {nombre: "Ulises"}));
![Page 558: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/558.jpg)
Vista
Anatomía de una vista
• Un modelo del que se extraen los datos
• Un template que se rendea con los datos del modelo
• Un nodo del DOM donde se inserta el template rendeado
• Un método .render() que se encarga de ejecutar este proceso
![Page 559: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/559.jpg)
Vista
el Vista Modeloescuchaactualiza
![Page 560: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/560.jpg)
Vista
En Backbone:
.model: el modelo asociado a la vista
.tagName: la etiqueta para generar el nodo del DOM
.attributes: los atributos para generar el nodo
.el: el nodo, ya creado
.$el: el nodo, envuelto con jQuery (o Zepto)
.$: un atajo a jquery pero con el scope fijado en .el
.render: el método que se encarga de rendear el template y actualizar el contenido de .el
![Page 561: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/561.jpg)
Vista
var MiVista = ProJS.View.extend({ init: function(options) { this._super(options); }, tagName: "div", attributes: {"class": "box large"}, template: "<h1> <%= nombre %> </h1>", render: function() { var data = this.model.toJSON(); this.$el.html( _.template(this.template, data) ); return this; }});
var producto = new Producto({nombre: "Vino"}), miVista = new MiVista({model: producto}).render();
$("body").append(miVista.el);
![Page 562: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/562.jpg)
Vista
Ejercicio: una vista sencilla
tema4/view-1/index.html
Crea una vista que utilice el template #producto-template para mostrar una instancia de Producto
![Page 563: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/563.jpg)
Vista
Ejercicio: vistas y colecciones
tema4/view-2/index.html
Crea una colección que se inicialice con los datos de la ruta /products
Para cada uno de los modelos:
Instancia una vista VistaListado
Muéstrala por pantalla
Una pista: ¡las colecciones emiten eventos!
![Page 564: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/564.jpg)
Vista
La vista debería “escuchar” al modelo
Cambios automáticos cuando el modelo cambia
El patrón habitual:
var VistaListado = ProJS.View.extend({ init: function (options) { this._super(options); this.model.on("change", bind(this, this.render)); }, /* ... */});
![Page 565: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/565.jpg)
Y ahora, ¿qué?
Tenemos Modelo y Vista
• Todo el mundo está de acuerdo en estos dos puntos
• Datos + presentación
• Todavía falta algo...
![Page 566: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/566.jpg)
MV*
MV*
• El papel del Controlador no está tan claro
• Gestionar la interacción?
• Gestionar los eventos de la vista?
• Gestionar las rutas de la página?
• Gestionar al modelo?
• ...
![Page 567: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/567.jpg)
MV*
La visión tradicional:
Modelo Controlador Vista
![Page 568: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/568.jpg)
MV*
En JavaScript...
M Controlador V
![Page 569: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/569.jpg)
MV*
En JavaScript...
M Controlador V
TemplateProxy ¡Todo lo demás!
![Page 570: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/570.jpg)
Controlador
El modelo “estándar” de Backbone.js
• Nadie lo dice abiertamente, pero:
• No hay Backbone.Controller
• La vista propiamente dicha es el template
• Pero Backbone.View gestiona la interacción...
• Es decir, hace de controlador
![Page 571: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/571.jpg)
Controlador
Si no te he convencido...
¿Quién reacciona al input del usuario?
Backbone.View
¿Quién se encarga de actualizar los datos del modelo según ese input?
Backbone.View
¿Dónde se programa la lógica del interfaz de usuario?
Backbone.View
![Page 572: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/572.jpg)
Controlador
Escuchar eventos en la vista:
var VistaProducto = ProJS.View.extend({ events: { "click a": "marcarComoActivo" }, init: function(options) { this._super(options); this.template = $("#template-producto").html(); this.model.on("change", bind(this, this.render)); },
// Event handlers marcarComoActivo: function() { this.model.set({active: true}); }
/* ... */});
![Page 573: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/573.jpg)
Controlador
Ejercicio: cogiendo el feeling del controlador
tema4/controller-1/index.html
Haz que las vistas VistaListado:
- Escuchen los cambios del modelo y se auto-rendeen
- Escuchen el evento click en el <a> dentro de this.el y lo asocien a marcarComoActivo
- marcarComoActivo pone a true la propiedad “activo” del modelo
- Si la propiedad “activo” del modelo es true, añade la clase CSS “active” a this.el (que debería ser un <li>)
![Page 574: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/574.jpg)
Controlador
El ejemplo anterior tiene problemas:
¿Cómo podemos decirle a los demás elementos que se desactiven?
¿Cómo podemos avisar al resto de la aplicación que se ha seleccionado un nuevo Producto?
![Page 575: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/575.jpg)
MV*
¡Un Mediador!
• La mejor solución para coordinar componentes de una página
• Muy bajo acoplamiento:
- Modificar los componentes sin problemas
- Añadir o eliminar funcionalidad en la página
• MV* + Mediador = un patrón muy común y muy flexible
![Page 576: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/576.jpg)
MV*
Un ejemplo:
tema4/controller-2/index.html
Fíjate como VistaListado simplemente notifica al mediador
Y el mediador es quien se encarga de orquestar los demás elementos
Las ventajas son:
Tenemos todo el flujo “a vista de pájaro” de la página en un solo sitio: el mediador
Ningún componente está acoplado a ningún otro, solo notifica a su mediador
![Page 577: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/577.jpg)
MV*
Ejercicio: un poco de todo!
Modifica el ejemplo anterior para que al hacer click en un elemento de la barra lateral se muestre ese modelo con una vista VistaProducto (la tabla de los primeros ejercicios)
![Page 578: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/578.jpg)
Testing
made with love by Redradix (www.redradix.com)
![Page 579: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/579.jpg)
¿Qué es?
Comprobación automática del código
• Organizada por casos
• Cada caso comprueba un aspecto
• Comparando el resultado obtenido con el esperado
![Page 580: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/580.jpg)
¿Para qué sirve?
¡Para garantizar que todo funciona!
• Que el nuevo código es correcto
• Que no se ha roto nada de lo anterior
• Que una refactorización no ha introducido bugs
![Page 581: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/581.jpg)
¿En JavaScript?
Una práctica que va penetrando poco a poco
• Aunque sigue sin estar muy extendida
• Necesaria para aplicaciones complejas
• En general, una garantía de calidad
![Page 582: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/582.jpg)
Testing
Hay muchos tipos de tests:
• Unitarios: comprueban un componente o una parte específica del código
• Integración: comprueban la interacción de componentes
• Aceptación: comprueban los requisitos del proyecto
• Regresión: comprueban la corrección de cambios
• etc...
![Page 583: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/583.jpg)
Tests Unitarios
La idea de test unitario es muy simple:
• Dado un componente del sistema
• Para cada caso posible
• Comprobar que se comporta de la manera adecuada
![Page 584: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/584.jpg)
Test Unitarios
var Contador = ProJS.Class.extend({ init: function() { this.i = 0; }, get: function() { return this.i; }, inc: function() { this.i++; }, dec: function() { this.i--; }, reset: function() { this.i = 0; }});
![Page 585: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/585.jpg)
Test Unitarios
¿Cómo podríamos comprobar, programáticamente, que Contador funciona bien?
Haciendo algo así:
➡ tema5/unitarios-1/index.html
![Page 586: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/586.jpg)
Test Unitarios
Es bastante tedioso!
• Mucha repetición de código similar
• Se puede abstraer bastante
![Page 587: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/587.jpg)
Test Unitarios
Segundo intento
➡ tema5/unitarios-2/index.html
![Page 588: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/588.jpg)
Test Unitarios
var ContadorTests = Test.extend({ casos: { debe_empezar_a_cero: function(contador) { var i = contador.get(); this.assertEqual(i, 0, "Empieza a %1".format(i)); },
// ... }});
![Page 589: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/589.jpg)
Jasmine
Estupenda librería de testing
• Al estilo rspec
• Sencilla
• Potente
• http://pivotal.github.com/jasmine/
![Page 590: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/590.jpg)
Jasmine
¿Qué pinta tiene?
• tema5/jasmine-1/index.html
describe("Conjunto de tests", function() { it("debería ser un caso válido", function() { expect(true).toBe(true); }); it("debería ser un caso con error", function() { expect(true).toBe(false); });});
![Page 591: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/591.jpg)
Jasmine
Test del contador con Jasmine
• tema5/jasmine-2/index.html
![Page 592: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/592.jpg)
Jasmine
Test asíncronos
• ¿Cómo testearías que esta función llama al cb con true?
• tema5/jasmine-3/index.html
function asyncFn(cb) { setTimeout(function() { cb(true); }, 250);}
![Page 593: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/593.jpg)
Jasmine
describe("Test asíncrono", function() { it("debería llamar al callback con true", function() { var result, callback = function(response) { result = response; }; runs(function() { asyncFn(callback); }); waitsFor(function() { return result == true; }, 300); runs(function() { expect(result).toBe(true); }); });});
![Page 594: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/594.jpg)
Intermedio: Jasmine
¡Testea alguna de las funciones que hemos visto!
• La que te parezca más confusa
• Documentación y “matchers” de Jasmine en
➡ http://pivotal.github.com/jasmine/
![Page 595: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/595.jpg)
Jasmine
Jasmine en la consola:
• Cambiar a ConsoleReporter
• Y un poco de magia funcional...
➡ tema5/consola-1/index.html
![Page 596: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/596.jpg)
Jasmine
var lazyPrint = (function() { var buffer = "", print = function() { console.log(buffer); buffer = ""; }; print = debounce(print, 300); return function(msg) { buffer += msg; print(); };}());
![Page 597: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/597.jpg)
Jasmine
¿Para qué sirve Jasmine en la consola?
• Dejar la página libre
• Poder cargar nuestro propio HTML
•¡Testear interacciones e interfaces!
![Page 598: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/598.jpg)
Test de Integración (interfaz)
Comprobar que el UI funciona correctamente
• Simular la interacción del usuario disparando eventos DOM
• Observar el estado del programa inspeccionando el interfaz
• Asegurar la correcta integración de los componentes de la página
![Page 599: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/599.jpg)
Jasmine
El resultado:
• tema5/integration/index.html
• Queremos testear que el intefaz funciona bien
• “Inc” incrementa el contador y el display
• “Dec” decrementa el contador y el display
• “Reset” lo pone a 0
• Salida por consola...
- Podríamos ver esta salida en algún emulador de DOM de node.js
- O hacer un reporter que se comunique con el servidor de integración continua
![Page 600: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/600.jpg)
Spam Mode: ON
Al escribir test JS acaba surgiendo un problema:
• ¡Los datos!
• ¿De dónde saco datos válidos para testear?
• ¿Del servidor?
- No es fácil de conseguir modificar/resetear un set de datos cada vez que ejecuto un test
- Dependencia del backend
• Lo ideal sería:
- Factorías de datos (estilo FactoryGirl)
- Simular la interacción con el servidor de forma inocua
![Page 601: Curso Javascript profesionales](https://reader033.vdocument.in/reader033/viewer/2022052601/558ebf791a28ab54778b457c/html5/thumbnails/601.jpg)
Solipsist.js
Solipsist.js es una librería auxiliar para testear
➡ https://github.com/WeRelax/solipsist-js
• Tests JS aislados
• Factorías
• Mocking de peticiones AJAX
• Otro uso: programar el frontend independiente del backend