Apuntes Javascript Avanzado

download Apuntes Javascript Avanzado

of 85

description

Este e s un libro

Transcript of Apuntes Javascript Avanzado

  • Apuntes de Javascript IINivel Avanzado

    JuanMa GarridoEste libro est a la venta en http://leanpub.com/apuntes-javascript-avanzado

    Esta versin se public en 2015-01-28

    This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishingprocess. Lean Publishing is the act of publishing an in-progress ebook using lightweight toolsand many iterations to get reader feedback, pivot until you have the right book and buildtraction once you do.

    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0Unported License

  • A mi abueloHijo, tu di que si, y luego haz lo que te de la gana (mi abuelo)

  • ndice general

    1. Prologo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

    2. Same-origin policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.1 JSONP vs CORS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

    3. JSONP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43.1 Peticiones JSONP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

    4. CORS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84.1 Peticiones CORS sencillas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

    5. El valor de this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95.1 En una funcin global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95.2 En un mtodo de un objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105.3 En un metodo de un prototipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115.4 En una funcin constructora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115.5 Utilizando call o apply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125.6 Utilizando bind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135.7 En una funcin asociada a un evento . . . . . . . . . . . . . . . . . . . . . . . . 13

    6. Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157. Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    7.1 Encadenamiento de Prototipos (Prototype Chaining) . . . . . . . . . . . . . . . . 227.2 Moviendo metodos re-utilizables al prototypo . . . . . . . . . . . . . . . . . . . . 247.3 Herencia slo del prototipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267.4 Funcin constructora temporal F() . . . . . . . . . . . . . . . . . . . . . . . . . . 277.5 Encapsulando la herencia en una funcin . . . . . . . . . . . . . . . . . . . . . . 297.6 Robando el constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

    8. Contexto de Ejecucin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328.1 Objeto Variable (Variable Object) . . . . . . . . . . . . . . . . . . . . . . . . . . 328.2 Fases de Procesamiento del Cdigo . . . . . . . . . . . . . . . . . . . . . . . . . 358.3 Tipos de Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378.4 Hoisting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

    9. Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

  • NDICE GENERAL

    9.1 Ciclo de vida de una Funcin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4210.Patrones de Cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

    10.1 Separacin de capas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4510.2 Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4510.3 Init-time branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4610.4 Lazy Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4710.5 Objeto de Configuracin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4810.6 Propiedades y Mtodos Privados . . . . . . . . . . . . . . . . . . . . . . . . . . . 4910.7 Mtodos Privilegiados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4910.8 Funciones Privadas como Mtodos Pblicos (Revealing Module Pattern ) . . . . . 5010.9 Funciones Inmediatas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5110.10Memoization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5310.11 Patrn Modulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5410.12 Patrn Sandbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

    11.Patrones de Diseo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5711.1 Patrn Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5711.2 Patrn Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5811.3 Patrn Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6011.4 Patrn Mixins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6111.5 Patrn Decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6211.6 Patrn Faade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6411.7 Patrn Observer Subscriber/Publisher . . . . . . . . . . . . . . . . . . . . . . . 6511.8 Patrn Mediator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

    12.Unit Testings en Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7012.1 Unit Testings (pruebas unitarias) . . . . . . . . . . . . . . . . . . . . . . . . . . . 7012.2 TDD y BDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7212.3 Testing Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7212.4 Sinon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

  • 1. PrologoEste libro contiene la segunda parte de los materiales que he ido realizando para diferentestrainings JAVASCRIPT impartidos desde 2010.Esta segunda parte abarca conceptos ms avanzados de Javascript incluyen:

    Peticiones de datos a servidores y soluciones (Same-Origin Policy, JSONP, CORS) Javascript a fondo (scope, valor de this, prototype, contexto de ejecucin) Javascript orientado a objetos (prototype, herencia) Cmo estructurar mejor tu codigo JS (patrones de diseo y de codigo) Cmo testear tu codigo js (unit testings)

    Los conceptos cubiertos en este libro te permitiran que tu cdigo JS sea orientado a objetos,testado, escalable, ms comprensible y ms organizado.Espero que este libro te ayude a entender/implementar el codigo javascript que necesites.Cualquier feedback ser bien recibido :)

    1.1 ReferenciasAdemas de los enlaces reflejados, este material est basado en los siguientes libros:

    JavaScript: The Good Parts by Douglas Crockford Object-Oriented JavaScript by Stoyan Stefanov JavaScript Patterns by Stoyan Stefanov

    1.2 AgradecimientosGracias a @gemmabeltra por la super-portada del libro (y por aguantarme en general)A @amischol por elevar mi nivel de javascript y el de todos los que hemos trabajado a su lado(cuando nosotros vamos, l ya tiene su chalet alli montado)A @cvillu por animarme a escribir el libro y descubrirme LeanPub (South-Power!!!)A @crossrecursion por nuestras charlas/reuniones hablando de Javascript (me excitas intelec-tualmente)Y a @softonic por darme la oportunidad de impartir los trainings JS y rodearme de tanta gentecrack en JavaScript. No hay universidad que me pueda ensear lo que he podido aprender alli.

    1

  • 2. Same-origin policyLa Same-Origin policy (politica del mismo origen) controla que slo que los scripts queprovengan del mismo origen (mismo esquema, hostname y puerto) y que son ejecutados endiferentes paginas (ventanas, tabs) puedan acceder sin restricciones a sus respectivos DOMMismo Origen:

    1 http://site.com2 http://site.com/3 http://site.com/my/page.html

    Diferente Origen:

    1 http://www.site.com (another domain)2 http://site.org (another domain)3 https://site.com (another protocol)4 http://site.com:8080 (another port)

    Esta politica se aplica tambien a las peticiones AJAX (XMLHttpRequest) lo que significa que slopodremos hacer peticiones AJAX al host que sirve la pagina web donde se ejecuta el cdigoLos WebSockets no estan sujeto a esta politica (con ellos podras comunicar partes en diferentesdominios)Esta politica viene implementada en TODOS los navegadores (antiguos y modernos)De forma nativa, slo podremos incluir recursos de otros dominios con los siguientes elementos:

    Archivos Javascript con Archivos CSS con Imgenes con Archivos Multimedia con y Plug-ins con , y Fuentes con @font-face Cualquier otra pagina con and

    Sin embargo existen maneras de saltarse esta politica: JSONP y CORS

    2.1 JSONP vs CORS

    2

  • Same-origin policy 3

    ..

    CORS y JSONP: Solicitudes AJAX entre dominios | formandome.es Sopa de Siglas: AJAX, JSON, JSONP y CORS | blog.koalite.com So, JSONP or CORS? | StackOverflow

    La recomendacin general es usar CORS siempre que se pueda, pero hay que tener en cuenta losiguiente:

    CORS soporta mas metodos HTTP (GET, PUT, POST, DELETE) que JSONP (slo GET) Puedes utilizar JSONP en cualquier navegador (antiguo y moderno). Sin embargo CORSsolo funcionar en algunos navegadores (los que soporten xhr2)

    Hay mas APIs publicas que ofrecen acceso a datos via JSONP que via CORS CORS (el servidor decide a quien da acceso y cmo) es mas seguro que JSONP (cross-originvia script injection)

    Con CORS hay un mejor manejo de errores que con JSONP Tanto CORS como JSONP requieren que el servidor est preparado para ellos

  • 3. JSONP

    ..

    Defining Safer JSON-P | json-p.org/ Remote JSON - JSONP | bob.ippoli.to JSONP: How Does it Work? | http://johnnywey.com/

    JSONP (JSON con Padding) es una tcnicamediante la que podemos obtener y tratar JSON desdeotros dominios (desde javascript).Con esta tecnica/hack obtenemos el JSON pasado como parametro a una funcion que se ejecutaen el cliente

    El problema

    Si desde la pagina MYsite.com ejecuto

    1 $.ajax({2 url: 'http://www.ANOTHERsite.com/datos.json',3 success: function(data) {4 console.log(data)5 }6 });

    el navegador (Chrome) me devuelve algo asi:

    1 Refused to connect to 'http://www.anothersite.com/datos.json' because it viol\2 ates the following Content Security Policy directive...

    debido a la Same-origin policy del objeto XMLHttpRequest Sin embargo si hacemos esto

    1

    si que podriamos obtener el JSON

    4

  • JSONP 5

    1 {2 "api_key": "224Wrf2asfSDfcea23reSDfqW",3 "status": "good",4 "name": "wikipedia",5 "date": "27-09-1995"6 }

    pero no podriamos acceder al JSON obtenido ya que no queda almacenado en niguna variable

    La solucin

    La solucion para poder tratar este JSON es preparar el servidor para que devuelva el JSONenvuelto en la llamada a una funcin

    1 handleMyJSONResponse ({2 "api_key": "224Wrf2asfSDfcea23reSDfqW",3 "status": "good",4 "name": "wikipedia",5 "date": "27-09-1995"6 });

    Asi, si definimos en el cliente una funcion global handleMyJSONResponse preparada para recibirun JSON como parametro, ya podriamos recibir y tratar estos datos desde JS.

    1 window.handleMyJSONResponse = function (datosJSON) {2 console.log (datosJSON);3 };

    Por convencin, el nombre de la funcin callback se especifica en un parmetro (jsonp, callbacko cualquier otro) de la URL que hace la peticion al servidor.

    1

    3.1 Peticiones JSONP

    Con cdigo nativo

    .. jsFiddle: Ejemplos JSONP con JS nativo

  • JSONP 6

    1 window.do_things = function (data) {2 console.log ( "do_things : %o", data.responseData.results );3 }45 function loadScript (id, src, callback) {67 // Crear elemento8 var script = document.createElement("script");910 // Atributos del script11 script.setAttribute("type", "text/javascript");12 script.setAttribute("src", src + "&callback=" + callback);13 script.setAttribute("id", id);1415 // Insertar script en la cabecera16 document.getElementsByTagName("head")[0].appendChild(script);1718 }1920 loadScript ("my_script_tag_id", "http://ajax.googleapis.com/ajax/services/sea\21 rch/web?v=1.0&q=casas+alquiler", "do_things");

    Con jQueryJQuery se encarga (de forma transparente al developer) de darle un nombre a la funcion callback,pasarla en la peticion, crearla globalmente en el cliente y se encarga tambin de aadir y eliminarel tag script utilizado internamente

    ..

    jsFiddle: Ejemplos JSONP jQuery jsFiddle: Ejemplo JSONP jQuery (Google Search Form)

    1 $.getJSON(2 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=casas+alquiler&c\3 allback=?',4 function( googleResults) {5 console.log ( "$.getJSON : %o", googleResults.responseData.results );6 }7 );89 $.ajax({10 url: "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=casas+alqui\11 ler",12 dataType: "jsonp",

  • JSONP 7

    13 success: function( response ) {14 console.log ( "$.ajax minimal : %o", response.responseData.results );15 }16 });

    APIs publicas

    La mayoria de las APIs publicas vienen ya preparadas para devolver JSONP:

    .. API Notebook

    Instagram

    1 https://api.instagram.com/v1/tags/coffee/media/recent?access_token=fb2e77d.47\2 a0479900504cb3ab4a1f626d174d2d&callback=callbackFunction

    Github

    1 https://api.github.com/?callback=foo

    Flickr

    1 https://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api\2 _key=929033444e3a0d9a3859195d56d36552

    LinkedIn

    1 https://api.linkedin.com/v1/people/~:(id)?callback=firstNameResponse&error-ca\2 llback=firstNameError

    SoundCloud

    1 https://api.soundcloud.com/tracks.json?client_id=YOUR_CLIENT_ID&callback=proc\2 essTracks

  • 4. CORS

    ..

    Enable cross Cross-domain Ajax with Cross-Origin Resource Sharing | Nicholas C. Zakas Cross-Origin Resource Sharing | w3.org

    Cross-Origin Resource Sharing (CORS) permite realizar peticiones a otros dominios siemprey cuando el dominio de destino (servidor) est de acuerdo en recibir peticiones del dominio deorigen.Es una tecnologa (especificacin W3C) implementada en los navegadores actuales, que inter-cambia ciertas cabeceras HTTP con el servidor de destino para saber si debe permitir o no elintercambio de datos.Cada vez ms APIs publicas permiten CORS pero la mayoria ofrecen solo JSONP.

    4.1 Peticiones CORS sencillas

    con jQuery

    ..

    Ejemplo CORS request (HTML) Ejemplo CORS request (JSON)

    Una peticion CORS utilizando jQuery es, en la mayoria de los casos, transparente al cliente, yaque si nuestro navegador lo soporta y el servidor (por ejemplo GitHub) est preparado, puedeser tan sencillo como esto:

    1 $.ajax({2 url: "https://api.github.com/users/juanmaguitar/repos",3 success: function( response_json ) {4 console.info (response_json);5 }6 });

    8

  • 5. El valor de this

    .. value of this | quirksmode.org

    El valor this es una propiedad del Contexto de Ejecucin

    1 activeExecutionContext = {2 VO: {...},3 this: thisValue4 };

    El valor de this queda determinado al entrar en el contexto de ejecucin (al llamar a la funcin)y no se puede cambiar mientras el cdigo est corriendo en el contextoEl valor de this en el Cdigo Global es siempre el Objeto Global

    1 // explicit property definition of2 // the global object3 this.a = 10; // global.a = 104 alert(a); // 1056 // implicit definition via assigning7 // to unqualified identifier8 b = 20;9 alert(this.b); // 201011 // also implicit via variable declaration12 // because variable object of the global context13 // is the global object itself14 var c = 30;15 alert(this.c); // 30

    El valor de this en el Cdigo de Funcin depende de cmo se llame a esta funcin

    5.1 En una funcin globalCuando se llama a una funcin que est a nivel de programa, el valor de su this correspondeal objeto global

    9

  • El valor de this 10

    1 function f1(){2 return this;3 }4 >>> f1() === window; // global object5 true

    Nota: En ECMASCRIPT 5 el valor de this no se convierto al global cuando es null o undefined

    1 function f2(){2 "use strict"; // see strict mode3 return this;4 }5 >>> f2() === undefined;6 true

    More info:

    ECMAScript 5 support in Mozilla ECMA 262

    5.2 En un mtodo de un objetoCuando una funcin es llamada comomtodo de un objeto, su this se corresponde con el objetosobre el que se la llama

    1 var o = {2 prop: 37,3 f: function() {4 return this.prop;5 }6 };7 >>> o.f() === 378 true

    1 var o = {prop: 37};2 function independent() {3 return this.prop;4 }5 o.f = independent;6 >>> o.f() === 377 true

    la manera en que se define el mtodo no afecta al valor de this

  • El valor de this 11

    1 o.b = {g: independent, prop: 42};2 >>> o.b.g() === 423 true

    a this se le asigna el objeto ms cercano (la referencia ms inmediata)

    5.3 En un metodo de un prototipoSi el mtodo pertenece a un objeto que est en la cadena de prototipos, su this tambin secorresponder con el objeto sobre el que se le llama

    1 var Class = function (){}2 Class.prototype.f = function(){ return this.a + this.b; };34 var oInstance = new Class();5 oInstance.a = 1;6 oInstance.b = 4;78 >>> oInstance.f() === 59 true

    5.4 En una funcin constructoraSi la funcin se utiliza como constructor (con new), su this apuntar al nuevo objeto creado

    1 function Class(){ this.a = 37; }2 var o = new Class ();34 >>> o.a === 375 true67 function Class2(){ this.a = 37; return {a:38}; }8 o = new Class2 ();910 >>> o.a === 3811 true

  • El valor de this 12

    1 function Hero(name) {2 this.name = name;3 this.occupation = 'Ninja';4 this.whoAreYou = function() {5 return "I'm " + this.name + " and I'm a " + this.occupation;6 }7 }89 var h1 = new Hero('Michelangelo');10 var h2 = new Hero('Donatello');1112 >>> h1.whoAreYou() === "I'm Michelangelo and I'm a Ninja"13 true14 >>> h2.whoAreYou() === "I'm Donatello and I'm a Ninja"15 true1617 >>> h1.occupation = "Turtle Ninja Super Hero";18 >>> h1.whoAreYou() === "I'm Michelangelo and I'm a Turtle Ninja Super Hero"19 true

    5.5 Utilizando call o applySi en la llamada a la funcin utilizamos call o apply, podemos asociar this a un objetodeterminado (que pasaremos como parmetro)

    1 function add(c, d){2 return this.a + this.b + c + d;3 }45 var o = {a:1, b:3};67 // The first parameter is the object to use as 'this', subsequent8 // parameters are passed as arguments in the function call9 >>> add.call(o, 5, 7) === 16; // 1 + 3 + 5 + 7 = 1610 true1112 // The first parameter is the object to use as 'this', the second is an array\13 whose14 // members are used as the arguments in the function call15 >>> add.apply(o, [10, 20]) === 34 // 1 + 3 + 10 + 20 = 3416 true

  • El valor de this 13

    5.6 Utilizando bindTambien podemos hacer un bind a una funcin y asociarle de forma permanente como this elobjeto que queramos (que utilizar siempre, independientemente de cmo se la llame)

    1 Function.prototype.bind = function(scope) {2 var _function = this;3 return function() {4 return _function.apply(scope, arguments);5 }6 }78 alice = {9 name: "alice"10 }1112 eve = {13 name: "eve",14 talk: function(greeting) {15 return (greeting + ", my name is " + this.name);16 }.bind(alice) // >> eve.talk("hello") === "hello, my name is alice"20 true21 >>> eve.talk.call({name:"paco"},"HOLA") === "HOLA, my name is alice"22 true

    5.7 En una funcin asociada a un eventoCuando una funcin se utiliza como event handler, su this queda asociado al elemento queprovoca el evento

    1 // When called as a listener, turns the related element blue2 function bluify(e){3 this.style.backgroundColor = '#A5D9F3';4 e.preventDefault();5 }67 // Get a list of every link in the document8 var elements = document.getElementsByTagName('a');910 // Add bluify as a click listener so when the element is clicked on,11 // it turns blue

  • El valor de this 14

    12 for(var i=0 ; i

  • 6. PrototypeTodas las funciones tienen una propiedad prototype que contiene inicialmente un objetoPodemos aadir propiedades ymtodos a este objeto prototype. Tambin podemos reemplazarlocompletamente por otro objetoAl crear objetos usando una funcin como constructor (con new), estos objetos adquieren unenlace secreto (__proto__ en Firebug) que apunta al prototipo de esta funcin constructora (clase ) lo que les permite acceder a sus propiedades (y mtodos) como si fueran propias.Las propiedades propias del objetos tienen prioridad sobre las propiedades del prototipo con elmismo nombre

    1 function Person(gender) {2 this.gender = gender;3 console.log (this.gender + ' instantiated');4 }56 var person1 = new Person('Male');7 var person2 = new Person('Female');89 >>> person1.gender === 'Male'10 true11 >>> person2.gender === 'Female'12 true1314 >>> Person.prototype.type = 'Human being';1516 >>> person1.type === 'Human being'17 true18 >>> person2.type === 'Human being'19 true2021 person1.type = 'Super Hero';2223 >>> person1.type === 'Super Hero'24 true25 >>> person2.type === 'Human being'26 true

    Cadena de PrototiposLos objetos disponen de lo que se llama la cadena de prototipos

    15

  • Prototype 16

    Si un objeto foo no dispone de la propiedad bar al hacer foo.bar, Javascript buscar estpropiedad en su prototipo (el de la funcin constructora que lo cre)

    Si no lo encuentra ah, lo buscar en el prototipo de su prototipo Y asi hasta llegar al objeto de ms alto nivel, el objeto Object

    cadena de prototipos

    1 function Person(gender) {2 this.gender = gender;3 this.shoutGender = function () {4 return this.gender.toUpperCase();5 }6 }78 Person.prototype.sayGender = function() {9 return this.gender;10 };1112 var person1 = new Person('Male');1314 >>> person1.sayGender() === "Male"15 true16 >>> person1.shoutGender() === "MALE"17 true1819 >>> var genderTeller = person1.sayGender;2021 >>> genderTeller() === "Male"22 false23 >>> genderTeller === person1.sayGender

  • Prototype 17

    24 true25 >>> genderTeller === Person.prototype.sayGender26 true2728 >>> var Obj = {gender : 'Male'}2930 >>> genderTeller.call(Obj) === "Male"31 true3233 >>> var person2 = new Person('Female');34 >>> Person.prototype.shoutGender = function () {35 return "From the Class, youre " + this.gender.toUpperCase();36 }3738 >>> person1.shoutGender() === "MALE"39 true40 >>> person2.shoutGender() === "FEMALE"41 true4243 >>> delete person1.shoutGender44 true4546 >>> person1.shoutGender() === "MALE"47 false48 >>> person2.shoutGender() === "FEMALE"49 true50 >>> person1.shoutGender() === "From the Class, youre MALE"51 true5253 >>> person1.shoutGender = function () {54 return "I'm person1 and Im " + this.gender.toUpperCase();55 }5657 >>> person1.shoutGender() === "From the Class, youre MALE"58 false59 >>> person1.shoutGender() === "I'm person1 and Im MALE"60 true61 >>> person2.shoutGender() === "FEMALE"62 true

    El metodo hasOwnProperty()Cuando recorremos un objeto con un for-in pasamos por:

    Las propiedades propias del objeto Todas las propiedades accesibles a travs de la cadena de prototipos

  • Prototype 18

    Con el mtodo hasOwnProperty() podemos diferenciar las propiedades propias del objeto de lasdel prototipo

    1 function Gadget(name, color) {2 this.name = name;3 this.color = color;4 this.someMethod = function(){return 1;}5 }67 Gadget.prototype.price = 100;8 Gadget.prototype.rating = 3;910 var newtoy = new Gadget('webcam', 'black');1112 >>> for (var prop in newtoy) { console.log(prop + ' = ' +13 newtoy[prop]); }1415 name = webcam16 color = black17 someMethod = function () { return 1; }18 price = 10019 rating = 32021 >>> newtoy.hasOwnProperty('name');22 true2324 >>> newtoy.hasOwnProperty('price');25 false

    por tanto, para recorrer solamente las propiedades propias del objeto podemos hacer:

    1 >>> for (var prop in newtoy) {2 if (newtoy.hasOwnProperty(prop))3 console.log(prop + ' = ' + newtoy[prop]);4 }56 name = webcam7 color = black8 someMethod = function () { return 1; }

    El metodo isPrototypeOf()Cada objeto dispone del mtodo isPrototypeOf() que nos dice si un objeto en cuestin se estutilizando como prototipo de otro objeto

  • Prototype 19

    1 var monkey = {2 hair: true,3 feeds: 'bananas',4 breathes: 'air'5 };67 function Human(name) {8 this.name = name;9 }1011 Human.prototype = monkey;1213 >>> var george = new Human('George');14 >>> monkey.isPrototypeOf(george)15 true

    La propiedad constructorEl constructor del objeto prototype de una funcin constructora (clase), apunta a la funcinconstructora

    1 >>> function Dog(){this.tail = true;}23 >>>> Dog.prototype.constructor === Dog4 true56 >>>> Dog.prototype7 Dog {}89 >>> var myDog = new Dog()10 >>> myDog.__proto__11 Dog {}12 >>> myDog.__proto__.constructor === Dog13 true

    Sustituyendo completamente el prototypeLa cadena de prototipos es dinmica excepto cuando sustituimos completamente el objetoprototype

  • Prototype 20

    1 >>> function Dog(){this.tail = true;}2 >>> var benji = new Dog();3 >>> var rusty = new Dog();45 >>> typeof(benji.say) === "function"6 false78 >>> Dog.prototype.say = function(){return 'Woof!';}910 >>> typeof(benji.say) === "function"11 true1213 >>> benji.constructor === Dog14 true15 >>> typeof(benji.constructor.prototype.say) === "function"16 true17 >>> benji.constructor.prototype.tail === undefined18 true

    Si reescribimos el prototype con otro objeto perdemos la dinamicidad del prototipo

    1 >>> Dog.prototype = {paws:4, hair:true};23 >>> benji.paws === undefined //old instance cannot locate new prototype4 True5 >>> typeof(benji.say) === "function" //but still can access old6 prototype7 true89 >>> var lucy = new Dog()1011 >>> lucy.say !== undefined //new instance can locate new prototype12 false13 >>> lucy.paws !== undefined //but cannot access old prototype14 true1516 >>> lucy.constructor === Object17 true18 >>> benji.constructor === Dog19 true

    pero hay un comportamiento extrao

  • Prototype 21

    1 >>> lucy.constructor.prototype.paws === undefined // doesnt exist?2 true3 >>> benji.constructor.prototype.paws === undefined // and here it does?4 false

    Si hubiramos hecho

    1 >>> Dog.prototype = {paws:4, hair:true};2 >>> Dog.prototype.constructor = Dog;

    tendramos lo que se espera

    1 >>> lucy.constructor.prototype.paws === undefined // does exist!2 false3 >>> benji.constructor.prototype.paws === undefined // and here not!4 true

    Por tanto, siempre que sustituyamos completamente el prototype por otro objeto, convienerestituir el constructor de ese prototype

  • 7. Herencia7.1 Encadenamiento de Prototipos (Prototype

    Chaining)Es el mecanismo por defecto que describe el standard ECMA para implementar la herencia enJavascript

    1 function Shape(){2 this.name = 'shape';3 this.toString = function() {return this.name;};4 }56 function TwoDShape(){7 this.name = '2D shape';8 }910 function Triangle(side, height) {11 this.name = 'Triangle';12 this.side = side;13 this.height = height;14 this.getArea = function(){15 return this.side * this.height / 2;16 };17 }1819 TwoDShape.prototype = new Shape();20 Triangle.prototype = new TwoDShape();2122 TwoDShape.prototype.constructor = TwoDShape;23 Triangle.prototype.constructor = Triangle;2425 >>> var myTriangle = new Triangle(5,10)2627 >>> myTriangle.getArea() === 2528 true29 >>> myTriangle.hasOwnProperty("getArea")30 true3132 >>> myTriangle.toString() === "Triangle"33 true

    22

  • Herencia 23

    34 >>> myTriangle.hasOwnProperty("toString")35 false3637 >>> myTriangle.constructor === Triangle38 true3940 >>> myTriangle instanceof Shape41 true42 >>> myTriangle instanceof TwoDShape43 true44 >>> myTriangle instanceof Triangle45 true4647 >>> Shape.prototype.isPrototypeOf(myTriangle)48 true49 >>> TwoDShape.prototype.isPrototypeOf(myTriangle)50 true51 >>> Triangle.prototype.isPrototypeOf(myTriangle)52 true5354 >>> String.prototype.isPrototypeOf(myTriangle)55 false

    Encadenamiento de prototipos

  • Herencia 24

    1 >>> TwoDShape.prototype.hasOwnProperty("toString")2 true3 >>> Shape.prototype.hasOwnProperty("toString")4 false5 >>> myTriangle.hasOwnProperty("getArea")6 true7 >>> Triangle.prototype.hasOwnProperty("getArea")8 false910 >>> var td = new TwoDShape();1112 >>> td.constructor === TwoDShape13 true14 >>> td.toString() === "2D shape"15 true1617 >>> var s = new Shape()1819 >>> s.constructor === Shape20 true21 >>> s.toString() === "shape"22 true

    Se recomienda mover a los prototipos todas las propiedades/mtodos reutilizables, y dejar lasno-reutilizables como propias de las instancias

    7.2 Moviendo metodos re-utilizables al prototypo1 function Shape(){}23 // augment prototype4 Shape.prototype.name = 'shape';5 Shape.prototype.toString = function() {6 return this.name;7 };89 function TwoDShape(){}1011 // take care of inheritance12 TwoDShape.prototype = new Shape();13 TwoDShape.prototype.constructor = TwoDShape;1415 // augment prototype16 TwoDShape.prototype.name = '2D shape';17

  • Herencia 25

    18 function Triangle(side, height) {19 this.side = side;20 this.height = height;21 }2223 // take care of inheritance24 Triangle.prototype = new TwoDShape();25 Triangle.prototype.constructor = Triangle;2627 // augment prototype28 Triangle.prototype.name = 'Triangle';29 Triangle.prototype.getArea = function(){30 return this.side * this.height / 2;31 };3233 var myTriangle = new Triangle(5,10)

    Moving shared methods

    1 >>> TwoDShape.prototype.hasOwnProperty("toString")2 false3 >>> Shape.prototype.hasOwnProperty("toString")4 true5 >>> myTriangle.hasOwnProperty("getArea")6 false7 >>> Triangle.prototype.hasOwnProperty("getArea")

  • Herencia 26

    7.3 Herencia slo del prototipoEs un mecanismo ms eficiente ya que no se crean nuevas instancias slo para implementar laherenciaLa bsqueda por la cadena de prototipos es ms rpida (ya que no hay cadena de prototipos,todos los prototipos apuntan al mismo objeto )

    1 function Shape(){}23 // augment prototype4 Shape.prototype.name = 'shape';5 Shape.prototype.toString = function() {6 return this.name;7 };89 function TwoDShape(){}1011 // take care of inheritance12 TwoDShape.prototype = Shape.prototype;13 TwoDShape.prototype.constructor = TwoDShape;1415 // augment prototype16 TwoDShape.prototype.name = '2D shape';1718 function Triangle(side, height) {19 this.side = side;20 this.height = height;21 }2223 // take care of inheritance24 Triangle.prototype = TwoDShape.prototype;25 Triangle.prototype.constructor = Triangle;2627 // augment prototype28 Triangle.prototype.name = 'Triangle';29 Triangle.prototype.getArea = function(){return this.side * this.height /30 2;}

  • Herencia 27

    Herencia solo del prototipo

    1 >>> Triangle.prototype.hasOwnProperty("getArea")2 true3 >>> Shape.prototype.hasOwnProperty("getArea")4 true5 >>> Shape.prototype.hasOwnProperty("toString")6 true7 >>> Triangle.prototype.hasOwnProperty("toString")8 true

    El problema de este mtodo es que al apuntar todos los prototipos al mismo objeto, cuandomodificamos alguno de los prototipos, los modificamos todos.

    1 >>> Triangle.prototype.name = 'Triangle';2 >>> var s = new Shape()3 >>> s.name4 "Triangle"

    7.4 Funcin constructora temporal F()Para solucionar esto podemos usar una funcin constructora temporal F() vacia y asignarle asu prototype el prototipo de la funcin constructora padreDe esta manera podemos hacer new F() y crear objetos que no tengan propiedades por si mismospero que hereden todo del prototype del padre

  • Herencia 28

    1 function Shape(){}23 // augment prototype4 Shape.prototype.name = 'shape';5 Shape.prototype.toString = function() {return this.name;};67 function TwoDShape(){}89 // take care of inheritance10 var F = function(){};11 F.prototype = Shape.prototype;12 TwoDShape.prototype = new F();13 TwoDShape.prototype.constructor = TwoDShape;1415 // augment prototype16 TwoDShape.prototype.name = '2D shape';1718 function Triangle(side, height) {19 this.side = side;20 this.height = height;21 }2223 // take care of inheritance24 var F = function(){};25 F.prototype = TwoDShape.prototype;26 Triangle.prototype = new F();27 Triangle.prototype.constructor = Triangle;2829 // augment prototype30 Triangle.prototype.name = 'Triangle';31 Triangle.prototype.getArea = function(){return this.side * this.height /32 2;};3334 >>> var myTriangle = new Triangle(5, 10);35 >>> myTriangle.getArea() === 2536 true37 >>> myTriangle.toString() === "Triangle"38 true3940 >>> var myShape = new Shape()41 >>> myShape.name === "shape"42 True4344 >>> Triangle.prototype.name = "super-Triangle"45 >>> myTriangle.name === "super-Triangle"46 true

  • Herencia 29

    47 >>> myShape.name === "shape"48 true

    Funcion Intermedia F()

    1 >>> myTriangle.__proto__.__proto__.__proto__.constructor === Shape2 true3 >>> myTriangle.__proto__.__proto__.constructor === TwoDShape4 true56 >>> myTriangle.__proto__.constructor === Triangle7 true

    7.5 Encapsulando la herencia en una funcinPodemos encapsular este cdigo en una funcin extend que nos facilite implementar la herencia

    1 function extend(Child, Parent) {2 var F = function(){};3 F.prototype = Parent.prototype;4 Child.prototype = new F();5 Child.prototype.constructor = Child;6 }78 function Shape(){};9 // augment prototype10 Shape.prototype.name = 'shape';

  • Herencia 30

    11 Shape.prototype.toString = function() {return this.name;};1213 function TwoDShape(){};14 extend(TwoDShape, Shape);15 TwoDShape.prototype.name = '2D shape';1617 function Triangle(side, height) {18 this.side = side;19 this.height = height;20 }21 extend(Triangle, TwoDShape);22 Triangle.prototype.name = 'Triangle';23 Triangle.prototype.getArea = function(){return this.side * this.height /24 2;};2526 >>> var myTriangle = new Triangle(5, 10);27 >>> myTriangle.getArea() === 2528 true29 >>> myTriangle.toString() === "Triangle"30 true3132 >>> Triangle.prototype.hasOwnProperty("getArea")33 true34 >>> Shape.prototype.hasOwnProperty("getArea")35 false36 >>> Shape.prototype.hasOwnProperty("toString")37 true38 >>> Triangle.prototype.hasOwnProperty("toString")39 false

    7.6 Robando el constructorOtro patrn para implementar la herencia es llamando al constructor padre desde el constructorhijo mediante apply o call.De esta manera las propiedades del padre son recreadas como propias en el hijo (son valoresnuevos, no referencias a objetos)

  • Herencia 31

    1 function Shape(id) {2 this.id = id;3 }4 Shape.prototype.name = 'shape';5 Shape.prototype.toString = function(){return this.name;};67 function Triangle() {8 Shape.apply(this, arguments);9 }10 Triangle.prototype = new Shape();11 Triangle.prototype.name = 'Triangle';1213 >>> var myTriangle = new Triangle(101)14 >>> myTriangle.name === "Triangle"15 true16 >>> myTriangle.toString() === "Triangle"17 true18 >>> myTriangle.hasOwnProperty("name")19 false20 >>> myTriangle.hasOwnProperty("id")21 true22 >>> myTriangle.hasOwnProperty("toString")23 false

  • 8. Contexto de EjecucinHay 3 Tipos de Cdigo Ejecutable en ECMAScript:

    Cdigo Global: El cdigo que est a nivel de Programa. No incluye el cdigo que estdentro de las funciones

    Cdigo de Funcin: El cdigo dentro de una funcin Cdigo de Eval: El cdigo dentro de una expresin eval

    Cuando alguno de estos tipos de cdigo se ejecuta, lo hace dentro de un Contexto de EjecucinLos contextos de ejecucin forman una pila.Es decir, primero se ejecutar cdigo global en su propio contexto de ejecucin, este cdigo puedellamar a una funcin que se ejecutar en su propio contexto de ejecucin, y as sucesivamenteCon cada nueva invocacin a una funcin se entra en un nuevo contexto de ejecucin

    ..

    Activation Object & Variable Object | perfectionkills.com Execution Contexts | dmitry-soshnikov.com Functions and Execution Contexts | blog.tuenti.com

    8.1 Objeto Variable (Variable Object)1 AbstractVO (generic behavior of the variable instantiation process)2 3 > GlobalContextVO4 (VO === this === global)5 6 > FunctionContextVO7 (VO === AO, object and are added)

    Cada contexto de ejecucin tiene lo que se llama un Objeto Variable.Las variables ( var, VariableDeclaration), funciones (FunctionDeclaration, FD) y parmetrosformales de la funcin declaradas en el contexto son aadidas como propiedades de este ObjetoVariable

    En un cdigo globalCuando se entra en el contexto de ejecucin de un Cdigo Global, se utiliza un Objeto Globalcomo Objeto Variable.

    32

  • Contexto de Ejecucin 33

    1 VO(globalContext) === global;

    El Objeto Global es el objeto que se crea antes de entrar en ningn contexto de ejecucin. Suspropiedades son accesibles desde cualquier parte del cdigo, y existe durante la ejecucin delprograma.

    1 /* remember that `this` refers to global object when in global scope */2 var GLOBAL_OBJECT = this;3 var foo = 1;4 GLOBAL_OBJECT.foo; // 15 foo === GLOBAL_OBJECT.foo; // true6 function bar(){}7 typeof GLOBAL_OBJECT.bar; // "function"8 GLOBAL_OBJECT.bar === bar; // true

    1 >>> var a = 'test'2 >>> a === 'test' // directly, is found in VO(globalContext): "test"3 true4 >>> window === this5 true6 >>> window['a'] === 'test' // indirectly via global===VO(globalContext):7 true8 >>> a === this.a9 true10 >>> var aKey = 'a';11 >>> window[aKey] === 'test' // indirectly, with dynamic property name: "test"12 true

    En un cdigo de funcinCuando se entra en el contexto de ejecucin de un Cdigo de Funcin, se utiliza un Objeto deActivacin (AO) como Objeto Variable.

    1 VO(functionContext) === AO;

    Un Objeto de Activacin es creado al entrar en el contexto de una funcin e inicializado con lapropiedad arguments (objeto arguments con las propiedades callee y length)

    .. Objeto de Activacin | interglacial.com

  • Contexto de Ejecucin 34

    1 function foo(x, y, z) {23 // quantity of defined function arguments (x, y, z)4 console.log(foo.length == 3); // true56 // quantity of really passed arguments (only x, y)7 console.log(arguments.length === 2); // true89 // reference of a function to itself10 console.log(arguments.callee === foo); // true1112 // parameters sharing13 console.log(x === arguments[0]); // true14 console.log(x === 10); // true1516 arguments[0] = 20;17 console.log(x === 20); // true1819 var x = 30;20 console.log(arguments[0] === 30); // true2122 // however, if we dont pass and argument z23 // related index-property of the arguments24 // is not linked with z2526 var z = 40;27 console.log(arguments[2] === undefined); // true28 console.log(z === 40); // true2930 arguments[2] = 50;31 console.log(arguments[2] === 50); // true3233 console.log(arguments);34 console.log(arguments[2]);3536 }3738 foo(10, 20);

    ..

    Variable Object | dmitrysoshnikov.com Execution context within JavaScript (Varia-ble/Activation Object) | gist.github.com

  • Contexto de Ejecucin 35

    8.2 Fases de Procesamiento del CdigoEl procesamiento del cdigo (al llamar a una funcin) se divide principalmente en 2 fases:

    1. La entrada en el Contexto de Ejecucin (preparamos el terreno)2. La ejecucin del Cdigo

    1. Al entrar en el Contexto de EjecucinAl entrar en el Contexto de Ejecucin (pero antes de la ejecucin del cdigo), el Objeto Variablese rellena con las siguientes propiedades (y en este orden):1.- Para cada Parmetro Formal de la funcin (si estamos en el contexto de ejecucin de unafuncin)

    Se crea una propiedad en elObjeto Variable con el mismo nombre y valor que el parmetroformal

    Si no se le pasa el parmetro a la funcin, se crea una propiedad en el Objeto Variable conel mismo nombre y con valor undefined

    2.- Para cada Declaracin de Funcin (FunctionDeclaration, FD)

    Se crea una propiedad en elObjeto Variable con el mismo nombre y con su correspondienteobjeto-funcin como valor

    Si el Objeto Variable ya contiene una propiedad con el mismo nombre, se reemplaza suvalor y atributos

    3.- Para cada Declaracin de Variable (var, VariableDeclaration)

    Se crea una propiedad en el Objeto Variable con el nombre de la variable y con el valorundefined

    Si el Objeto Variable ya contiene una propiedad con el mismo nombre, esta declaracin devariable NO reemplaza su valor

    1 function test(a, b) {2 var c = 10;3 function d() {}4 var e = function _e() {};5 (function x() {});6 }7 test(10); // call

    al entrar en el contexto de la function test con el parmetro pasado 10, elObjeto de Activacinqueda asi:

  • Contexto de Ejecucin 36

    1 AO(test) = {2 a: 10,3 b: undefined,4 c: undefined,5 d: 6 e: undefined7 };

    2. Al empezar la Ejecucin del CdigoAl empezar la Ejecucin del Cdigo el Objeto de Activacin (Objeto Variable) ya est relleno consus propiedades (aunque no todas ellas tienen los valores reales pasados, la mayora tienen elvalor inicial undefined ): en el ejemplo anterior el Objeto de Activacin (AO/VO) se modificara asi durante lainterpretacin del cdigo

    1 AO['c'] = 10;2 AO['e'] = ;

    1 (function () {23 console.log (typeof(x) === 'function'); // true45 var x = 10;6 console.log (x === 10); // true78 x = 20;9 function x() {}1011 console.log (x === 20); // true1213 }())

    al entrar en el Contexto de Ejecucin

  • Contexto de Ejecucin 37

    1 VO = {};2 VO['x'] = 3 // found var x = 10;4 // if function "x" would not be already defined5 // then "x" be undefined, but in our case6 // variable declaration does not disturb7 // the value of the function with the same name8 VO['x'] =

    y al ejecutar el cdigo

    1 VO['x'] = 10;2 VO['x'] = 20;

    8.3 Tipos de FuncionesUna Function Declaration (FD) es una funcin que:

    Tiene un nombre obligatorio En el cdigo puede aparecer a nivel raz o en el cuerpo de otra funcin Se guardan en elObjeto Variable delContexto de Ejecucin (es decir, en tiempo de ejecucinya estn disponibles)

    1 foo();23 function foo() {4 alert('foo');5 }

    Una Function Expression (FE) es una funcin que:

    Puede tener un nombre opcional En el cdigo slo puede aparecer en la posicin de una expresin Su definicin no afecta al Objeto Variable del Contexto de Ejecucin Se crea en tiempo de ejecucin

  • Contexto de Ejecucin 38

    1 var foo = function () {2 alert('foo');3 };45 foo();

    1 // in parentheses (grouping operator) can be only an expression2 (function foo() {});3 // in the array initialiser also only expressions4 [function bar() {}];5 // comma also operates with expressions6 1, function baz() {};

    pese a que una FE puede tener nombre, las distinguimos de una FD en que las FE slo puedeestar en la posicin de una expresin

    1 // FE is not available neither before the definition2 // (because it is created at code execution phase),3 alert(foo); // "foo" is not defined4 (function foo() {});5 // nor after, because it is not in the VO6 alert(foo); // "foo" is not defined

    las FE son creadas en tiempo de ejecucin

    1 var foo = {};23 (function initialize() {4 var x = 10;5 foo.bar = function () {6 alert(x);7 };8 })();910 foo.bar(); // 10;11 alert(x); // "x" is not defined

    Si queremos llamar a una funcin directamente desde su definicin y la funcin no est en unaexpression position, tendremos que encerrarla entre parntesisCon esto, lo que hacemos en transformar manualmente la funcin en una Function Expression(FE)

  • Contexto de Ejecucin 39

    1 (function foo(x) {2 alert(x);3 })(1); // OK, it's a call, not a grouping operator, 1

    1 1, function () {2 alert('anonymous function is called');3 }();45 // or this one6 !function () {7 alert('ECMAScript');8 }();910 // and any other manual11 // transformation

    en el caso en que la funcin ya est en una expression position, no hacen falta los parntesis

    ..

    Functions | dmitrysoshnikov.com Understanding Delete | perfectionkills.com Fun-ctions and Scope | MDN

    8.4 HoistingSe le llama Hoisting al efecto particular que tiene el intrprete interno de separar la definicinde una variable en declaracin e inicializacion, y de mover las declaraciones al principio de lafuncin (aplicandoles el valor undefined)

    1 var joe = plumber2 // var joe

  • Contexto de Ejecucin 40

    .. Hoisting Explained | net.tutsplus.com Hoisting en Javascript | etnassoft.com

  • 9. ScopeEn la creacin de una funcin se define su propiedad (interna) Scope que es la lista jerrquicade todos los Objetos Variable de sus padres (que estan por encima de su contexto)En la llamada a una funcin se crea el ScopeChain (cadena de mbitos) del contexto de ejecucinque es: su Objeto de Activacin + la propiedad Scope de esta funcinLa resolucin de identificadores ( Identifier Resolution ) es el proceso en el cual se determina aqu Objeto Variable dentro de la cadena de mbitos pertenece una variable determinada

    1 var x = 10;23 function foo() {4 var y = 20;5 function bar() { alert(x + y); }6 return bar;7 }89 foo()(); // 30

    Al llamar a la funcin su Contexto de Ejecucin queda asi

    1 activeExecutionContext = {2 VO: {...}, // or AO3 this: thisValue,4 Scope: [ // Scope chain5 // list of all variable objects6 // for identifiers lookup7 ]8 };

    donde su Scope seria

    1 Scope = AO + [[Scope]]

    es decir

    1 Scope = AO + [VO1, VO2, ..., VOn]

    donde

    41

  • Scope 42

    1 var VO1 = {__parent__: null, ... other data}; -->2 var VO2 = {__parent__: VO1, ... other data}; -->3 // etc.

    ..

    Scope Chain | dmitrysoshnikov.com Functions Objects and Scope | p2pu.org Javascript Scope and Binding | alternateidea.com Functions and functions scope | MDN

    9.1 Ciclo de vida de una Funcin1 var x = 10;23 function foo() {4 var y = 20;56 function bar() {7 var z = 30;8 alert(x + y + z);9 }1011 bar();12 }1314 foo(); // 60

    Partimos del objeto global ya creado, que adems es la Variable Objeto del Contexto Global

    1 globalContext.VO === Global = {2 x: 103 foo: 4 };

    En la creacin de foo, la propiedad Scope de foo es

    1 foo.[[Scope]] = [2 globalContext.VO3 ];

    En la activacin de foo (al llamar a la funcin, al entrar en su contexto) , el objeto de activacindel contexto foo es

  • Scope 43

    1 fooContext.AO = {2 y: 20,3 bar: 4 };

    Y el Scope Chain del contexto foo queda

    1 fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.:23 fooContext.Scope = [4 fooContext.AO,5 globalContext.VO6 ];

    En la creacin de la funcin interna bar su _Scope es_

    1 bar.[[Scope]] = [2 fooContext.AO,3 globalContext.VO4 ];

    En la activacin de bar, el objeto de activacin del contexto bar es

    1 barContext.AO = {2 z: 303 };

    Y el Scope Chain de bar queda

    1 barContext.Scope = barContext.AO + bar.[[Scope]] // i.e.:23 barContext.Scope = [4 barContext.AO,5 fooContext.AO,6 globalContext.VO7 ];

    Asi, la resolucin de identificadores para x, y y z se hara asi

  • Scope 44

    1 - "x"2 -- barContext.AO // not found3 -- fooContext.AO // not found4 -- globalContext.VO // found - 10

    1 - "y"2 -- barContext.AO // not found3 -- fooContext.AO // found - 20

    1 - "z"2 -- barContext.AO // found 30

  • 10. Patrones de CdigoEstos patrones ayudan a organizar el cdigo, a mejorar su performance, a la creacin de objetosy a aplicar caractersticas perdidas en JS como propiedades privadas

    10.1 Separacin de capasLas 3 capas de una pgina web son

    Content (HTML) Presentation (CSS) Behavior (JavaScript)

    Estas capas deben estar lo ms separadas posibles, es decir no debemos tocar directamente desdeuna capa elementos pertenecientes a otra capa.Esto, en la capa de comportamiento (Javascript) significa:

    Evitar los tags con cdigo javascript dentro del marcado (intentar utilizar slolos que carguen otros archivos)

    Evitar attributos inline en las etiquetas como onclick, onmouseover etc.. (mejor capturar elevento desde un archivo externo utilizando los mtodos addEventListener o attachEvent)

    No alterar directamente propiedades del CSS (en todo caso, aadir o quitar clases) Aadir dinmicamente el marcado que no tenga sentido con el Javascript desactivado Que el cdigo JS quede en archivos *.js separados que incluyamos en la pgina

    10.2 Namespaces[creacin de objetos]Debemos evitar el uso de variables globales para minimizar las posibles colisiones de nombresde variable.Una manera de hacer esto es utilizando un Namespace, es decir, creando un nico objeto globaly haciendo que todas las variables y funciones que necesitemos sean propiedades de este objeto

    45

  • Patrones de Cdigo 46

    1 // global namespace2 var MYAPP = MYAPP || {};3 // sub-object4 MYAPP.event = {};5 // object together with the method declarations6 MYAPP.event = {7 addListener: function(el, type, fn) {8 // .. do the thing9 },10 removeListener: function(el, type, fn) {11 // ...12 },13 getEvent: function(e) {14 // ...15 }16 // ... other methods or properties17 };18 MYAPP.dom = {};19 MYAPP.dom.style = {};

    Podemos crear un mtodo que nos ayude con la creacin de elementos en el Namespace1 var MYAPP = MYAPP || {};2 MYAPP.namespace = function(name){3 var parts = name.split('.');4 var current = MYAPP;5 for (var i in parts) {6 if (!current[parts[i]]) {7 current[parts[i]] = {};8 }9 current = current[parts[i]];10 }11 }12 >>> typeof (MYAPP.dom.style) === "object"13 TypeError: MYAPP.dom is undefined14 >>> MYAPP.namespace('dom.style')15 >>> typeof (MYAPP.dom.style) === "object"16 true

    10.3 Init-time branching[performance]Cuando sabemos que cierta condicin no va a cambiar durante la ejecucin del programa,podemos hacer que nuestro cdigo evalu esa condicin una sola vez (durante la carga delprograma) y que devuelva funciones customizadas segn estas condiciones (ej.- FeatureDetection)

  • Patrones de Cdigo 47

    1 var MYAPP = {};2 MYAPP.event = {3 addListener: null,4 removeListener: null5 };67 if (typeof window.addEventListener === 'function') {8 MYAPP.event.addListener = function(el, type, fn) {9 el.addEventListener(type, fn, false);10 };11 MYAPP.event.removeListener = function(el, type, fn) {12 el.removeEventListener(type, fn, false);13 };14 } else if (typeof document.attachEvent === 'function'){ // IE15 MYAPP.event.addListener = function(el, type, fn) {16 el.attachEvent('on' + type, fn);17 };18 MYAPP.event.removeListener = function(el, type, fn) {19 el.detachEvent('on' + type, fn);20 };21 } else { // older browsers22 MYAPP.event.addListener = function(el, type, fn) {23 el['on' + type] = fn;24 };25 MYAPP.event.removeListener = function(el, type, fn) {26 el['on' + type] = null;27 };28 };

    10.4 Lazy Definition[performance]La Lazy Definition es muy parecida al Init-time branching, con la diferencia es que aqu lacustomizacin se realiza solo cuando se llama a la funcin por primera vez

    1 var MYAPP = {};2 MYAPP.myevent = {3 addListener: function(el, type, fn){4 if (typeof el.addEventListener === 'function') {5 MYAPP.myevent.addListener = function(el, type, fn) {6 el.addEventListener(type, fn, false);7 };8 } else if (typeof el.attachEvent === 'function'){9 MYAPP.myevent.addListener = function(el, type, fn) {10 el.attachEvent('on' + type, fn);

  • Patrones de Cdigo 48

    11 };12 } else {13 MYAPP.myevent.addListener = function(el, type, fn) {14 el['on' + type] = fn;15 };16 }17 MYAPP.myevent.addListener(el, type, fn);18 }19 };

    10.5 Objeto de Configuracin[creacin de objetos]Cuando una funcin necesita muchos parmetros (ms de 3 por ejemplo) es una buena ideaagruparlos en un objeto de configuracin y utilizar ste como nico parmetro (las propiedadesdel objeto sern los parmetros).Algunas ventajas de utlizar un objeto de configuracion son:

    El orden no importa Puedes setear slo los parmetros que necesites La funcin queda ms escalable El cdigo queda ms legible (los nombres de las propiedades estn presentes en la llamada)

    1 // a constructor that creates buttons2 var MYAPP = {};3 MYAPP.dom = {};4 MYAPP.dom.Button = function(text, conf) {5 var type = conf.type || 'submit';6 var font = conf.font || 'Courier';7 var color = conf.color || 'white';8 var b = document.createElement('input');910 b.type = type;11 b.font = font;12 b.color = color;13 b.value = text;14 return b;15 }1617 document.body.appendChild(new MYAPP.dom.Button('puuush'));18 var config = {19 font: 'Arial, Verdana, sans-serif',20 color: 'white'

  • Patrones de Cdigo 49

    21 };2223 var oMyButton = new MYAPP.dom.Button('puuush', config);24 document.body.appendChild(oMyButton);25 var oMyButton2 = new MYAPP.dom.Button('puuush', {color: 'red'});26 document.body.appendChild(oMyButton2);

    10.6 Propiedades y Mtodos Privados[creacin de objetos]Podemos definir propiedades/metodos privados en un objeto (aunque Javascript no tenga unasintaxis especial para ello) usando variables locales en la funcin constructora

    1 var MYAPP = {};2 MYAPP.dom = {};3 MYAPP.dom.Button = function(text, conf) {4 // private property5 var _styles = {6 font: 'Verdana',7 border: '1px solid black',8 color: 'black',9 };10 // private method11 function _setStyles() {12 for (var i in _styles) {13 b.style[i] = conf[i] || _styles[i];14 }15 }16 conf = conf || {};17 var b = document.createElement('input');18 b.type = conf['type'] || 'submit';19 b.value = text;20 _setStyles();21 return b;22 };2324 var oMyButton = new MYAPP.dom.Button('puuush', {color: 'blue'});25 document.body.appendChild(oMyButton);

    Para mejorar la legibilidad las variables/mtodos privados se marcan con _ delante del nombre

    10.7 Mtodos Privilegiados[creacin de objetos]

  • Patrones de Cdigo 50

    .. Private Members in JavaScript | Douglas Crockford

    Metodos Privilegiados (segn Douglas Crockford) son mtodos pblicos que pueden acceder amtodos o propiedades privadasActuan de filtro para hacer accesible alguna funcionalidad privada pero de una manera contro-ladaSon los metodos que definimos en la funcin constructora como parte del this, a diferencia delos metodos definidos en el prototipo.1 var Person = function(options){2 //private properties3 var _name = options.name4 var _birthYear = options.birthYear;5 //private method6 var _calculateAge = function(){7 var today = new Date();8 return today.getFullYear() - _birthYear;9 }10 //Privileged methods11 this.getAge = function(){12 return _calculateAge(); //calling private method13 }14 this.getName = function(){15 return _name.toUpperCase(); //return private variable filtered16 }17 }1819 //new Person instance20 var myPerson = new Person( {name:'Peter', birthYear:1983} );21 >>> myPerson.getAge() === 2922 true23 >>> myPerson.name === 'Peter'24 false25 >>> myPerson.name === undefined26 true27 >>> myPerson.getName() === 'PETER'28 true

    10.8 Funciones Privadas como Mtodos Pblicos(Revealing Module Pattern )

    [creacin de objetos]

  • Patrones de Cdigo 51

    ..

    Private Members in JavaScript | Douglas Crockford JavaScripts Revealing ModulePattern | blog.alexanderdickson.com

    Si queremosmantener intacta una funcin para nuestro cdigo interno, pero tambin queremosdar visibilidad externa a esa funcin, podemos asignar esa funcin a una propiedad pblica.A este patrn tambien se le conoce como Revealing Module Pattern

    1 var MYAPP = {};2 MYAPP.dom = (function(){3 var _setStyle = function(el, prop, value) {4 return 'setStyle';5 };6 var _getStyle = function(el, prop) {7 return 'getStyle';8 };9 return {10 setStyle: _setStyle,11 getStyle: _getStyle,12 yetAnother: _setStyle13 }; })()14 MYAPP.dom.setStyle = function(){ return Hey, Ho, Lets Go!! };15 >>> MYAPP.dom.setStyle() === 'Hey, Ho, Lets Go!!'16 true17 >>> MYAPP.dom.yetAnother() === 'setStyle'18 true

    10.9 Funciones Inmediatas[creacin de objetos]Otro patrn til para crear objetos es utilizar una funcin annima que devuelva un objeto yejecutarla inmediatamenteDe estamanera las variables dentro de la funcin son locales (declaradas con var) y son destruidascuando la funcin termina (siempre que no formen parte de un closure)

  • Patrones de Cdigo 52

    1 var MYAPP = {};2 MYAPP.dom = (function() {3 // initialization code...4 function _private() { console.log('_private'); }5 // ... body }6 return {7 getStyle: function(el, prop) {8 console.log('getStyle');9 _private();10 },11 setStyle: function(el, prop, value) {12 console.log('setStyle');13 }14 };15 })();

    Otra manera de crear objetos es ejecutar directamente la funcin annima y desde dentro hacerlas asignaciones que correspondan.Podemos pasarle parmetros a esta funcin inmediata (normalmente relacionadas con el entorno)y hacer nuestro cdigo ms rpido y robusto

    .. Self-Executing Anonymous Functions | Mark Dalgleish

    1 var MYAPP = {};2 (function(global, doc, ns, $, _undefined_){3 console.log ( window === global);4 console.log ( document === doc );5 console.log ( ns === MYAPP );6 console.log ( $ === jQuery );7 ns.existClass = (function () {8 if (doc.getElementsByClassName) {9 return function(sClassName) {10 return doc.getElementsByClassName(sClassName).length > 0;11 }12 }13 else {14 return function(sClassName) {15 return $("*").hasClass(sClassName);16 }17 }18 })();19 })(window, document, MYAPP, jQuery);20

  • Patrones de Cdigo 53

    21 MYAPP.existClass('hidden');22 MYAPP.existClass('___hidden____');

    si te estas preguntando para qu se define el parmetro undefined prueba esto en Safari:

    ..

    Understanding JavaScripts undefined | Angus Croll Type Checks | jQuery

    1 undefined = 5;2 (function( _undefined_ ){3 console.log ( undefined === _undefined_ );4 console.log ( typeof(undefined) === "undefined" );5 console.log ( typeof(_undefined_) === "undefined" );6 console.log ( myVar === undefined );7 console.log ( myVar === _undefined_ ); // this is faster8 console.log ( typeof(myVar) === "undefined" );9 })();

    10.10 Memoization[performance]

    ..

    Faster JavaScript Memoization For Improved Application Performance | Addy Osmani Memoization in JavaScript | Nicolas Garcia Belmonte

    Esta tcnica se utiliza para cachear resultados de operaciones costosas:

    Si no se ha realizado aun la operacin, se realiza y se guarda en cach (objeto o array) conun identificador nico

    Si ya se ha realizado, se devuelve el resultado directamente de la cach

  • Patrones de Cdigo 54

    1 var hasClassName = (function(){2 var cache = { };3 return function(element, className) {4 var re = (cache[className] ||5 (cache[className] = new RegExp('(?:^|\\s)' + className + '(?:\\s|$)') ));6 return re.test(element.className);7 };8 })();

    10.11 Patrn Modulo[creacin de objetos]

    .. A JavaScript Module Pattern | http://yuiblog.com/

    La idea del patrn modulo es la de encapsular la lgica privada y exponer solamente determinados mtodos pblico.Se aplica utilizando funciones autoejecutables que devuelven objetos

    1 var functionUtils = (function(){2 /* private `slice` method */3 function slice(arrayLike, index) {4 return Array.prototype.slice.call(arrayLike, index || 0);5 }6 return {7 /* exposed, public `bind` method */8 bind: function(fn, thisArg) {9 var args = slice(arguments, 2);10 return function() {11 return fn.apply(thisArg, args.concat(slice(arguments)));12 };13 }14 };15 })();

    10.12 Patrn Sandbox[creacin de objetos]

  • Patrones de Cdigo 55

    .. javascript-patterns | github shichuan

    El patrn Sandbox soluciona dos problemas que hay con el patrn Namespace :

    No se pueden crear 2 versiones de la misma aplicacin en la misma pgina ya que todocuelga del mismo objeto global (MYAPP)

    Largas rutas a resolver (y que escribir) para acceder a los metodos (MYAPP.utilities.array)

    El patrn Sandbox utiliza una funcin constructora global, en vez de un objeto esttico global.Al pasarle una funcin fpCallback a este constructor, se crear un objeto (box) donde estafuncin fpCallback tendr disponible los metodos que necesita.

    1 function Sandbox() {2 // turning arguments into an array3 var args = Array.prototype.slice.call(arguments),4 // the last argument is the callback5 callback = args.pop(),6 // modules can be passed as an array or as individual parameters7 modules = (args[0] && typeof args[0] === "string") ? args : args[0], i;89 // make sure the function is called10 // as a constructor11 if (!(this instanceof Sandbox)) {12 return new Sandbox(modules, callback);13 }1415 // add properties to `this` as needed:16 this.a = 1;17 this.b = 2;1819 // now add modules to the core `this` object20 // no modules or "*" both mean "use all modules"21 if (!modules || modules == '*') {22 modules = [];23 for (i in Sandbox.modules) {24 if (Sandbox.modules.hasOwnProperty(i)) {25 modules.push(i);26 }27 }28 }2930 // initialize the required modules

  • Patrones de Cdigo 56

    31 for (i = 0; i < modules.length; i += 1) {32 Sandbox.modules[modules[i]](this);33 }34 // call the callback35 callback(this);36 }3738 // any prototype properties as needed39 Sandbox.prototype = {40 name:"My Application",41 version:"1.0",42 getName:function () {43 return this.name;44 }45 };46 Sandbox.modules = {};47 Sandbox.modules.dom = function (box) {48 box.getElement = function () {};49 box.getStyle = function () {};50 box.foo = "bar";51 };52 Sandbox.modules.event = function (box) {53 // access to the Sandbox prototype if needed:54 // box.constructor.prototype.m = "mmm";55 box.attachEvent = function () {};56 box.detachEvent = function () {};57 };58 Sandbox.modules.ajax = function (box) {59 box.makeRequest = function () {};60 box.getResponse = function () {};61 };62 // how to use63 Sandbox(['ajax', 'event'], function (box) {64 console.log(box);65 });66 Sandbox('ajax', 'dom', function (box) {67 console.log(box);68 });69 Sandbox('*', function (box) {70 console.log(box);71 });

  • 11. Patrones de Diseo

    ..

    Patrones de Diseo con Javascript (Video) design-patterns - github shichuan

    11.1 Patrn Singleton[creacin de objetos]

    ..

    The Singleton Pattern | Addy Osmani Patrones de Diseo en Javascript: El patrn Singleton | pixelovers.com singleton - github shichuan

    La idea general de este patrn es la de asegurar que una clase genera una nica instancia, esdecir, limitar la instanciacin de una clase a un nico objeto

    1 var mySingleton = (function () {2 // Instance stores a reference to the Singleton3 var instance;4 function init() {5 // Singleton6 // Private methods and variables7 function privateMethod(){8 console.log( "I am private" );9 }10 var privateVariable = "Im also private";11 return {12 // Public methods and variables13 publicMethod: function () {14 console.log( "The public can see me!" );15 },16 publicProperty: "I am also public"17 };18 };1920 return {

    57

  • Patrones de Diseo 58

    21 // Get the Singleton instance if one exists22 // or create one if it doesn't23 getInstance: function () {24 if ( !instance ) {25 instance = init();26 }27 return instance;28 }29 };30 })();3132 // Usage:33 >>> var singleA = {}, singleB = {};34 >>> singleA === singleB35 false36 >>> singleA = mySingleton.getInstance()37 >>> singleB = mySingleton.getInstance()38 >>> singleA === singleB39 true

    11.2 Patrn Factory[creacin de objetos]

    ..

    The Factory Pattern | Addy Osmani factory - github shichuan

    El objetivo de este patrn es el de crear objetosEn vez de crear objetos directamente con new, utilizaremos un objeto Factory al que le pediremosque tipo de objeto queremos y ste objeto lo instanciar y nos lo devolverEste patrn es util en las siguientes situaciones:

    Cuando necesitamos repetir operaciones al crear objetos similares Cuando necesitamos generar diferentes instancias de objetos dependiendo del entorno Cuando trabajamos con pequeos objetos o componentes que comparten las mismaspropiedades

  • Patrones de Diseo 59

    1 // Types.js - Constructors used behind the scenes2 // A constructor for defining new cars3 function Car( options ) {4 // some defaults5 this.doors = options.doors || 4;6 this.state = options.state || "brand new";7 this.color = options.color || "silver";8 }910 // A constructor for defining new trucks11 function Truck( options){12 this.state = options.state || "used";13 this.wheelSize = options.wheelSize || "large";14 this.color = options.color || "blue";15 }1617 // FactoryExample.js18 // Define a skeleton vehicle factory19 function VehicleFactory() {}2021 // Define the prototypes and utilities for this factory22 // Our default vehicleClass is Car23 VehicleFactory.prototype.vehicleClass = Car;2425 // Our Factory method for creating new Vehicle instances26 VehicleFactory.prototype.createVehicle = function ( options ) {27 if( options.vehicleType === "car" ){28 this.vehicleClass = Car;29 }else{30 this.vehicleClass = Truck;31 }32 return new this.vehicleClass( options );33 };3435 // Create an instance of our factory that makes cars36 var carFactory = new VehicleFactory();37 var car = carFactory.createVehicle( {38 vehicleType: "car",39 color: "yellow",40 doors: 6 } );4142 // Test to confirm our car was created using the vehicleClass/prototype Car43 // Outputs: true44 console.log( car instanceof Car );45 // Outputs: Car object of color "yellow", doors: 6 in a "brand new" state46 console.log( car );

  • Patrones de Diseo 60

    Approach #1: Modify a VehicleFactory instance to use the Truck class

    1 var movingTruck = carFactory.createVehicle( {2 vehicleType: "truck",3 state: "like new",4 color: "red",5 wheelSize: "small" } );67 // Test to confirm our truck was created with the vehicleClass/prototype Truck8 // Outputs: true9 console.log( movingTruck instanceof Truck );1011 // Outputs: Truck object of color "red", a "like new" state12 // and a "small" wheelSize13 console.log( movingTruck );

    Approach #2: Subclass VehicleFactory to create a factory class that builds Trucks

    1 function TruckFactory () {}2 TruckFactory.prototype = new VehicleFactory();3 TruckFactory.prototype.vehicleClass = Truck;4 var truckFactory = new TruckFactory();5 var myBigTruck = truckFactory.createVehicle( {6 state: "omg..so bad.",7 color: "pink",8 wheelSize: "so big" } );910 // Confirms that myBigTruck was created with the prototype Truck11 // Outputs: true12 console.log( myBigTruck instanceof Truck );1314 // Outputs: Truck object with the color "pink", wheelSize "so big"15 // and state "omg. so bad"16 console.log( myBigTruck );

    11.3 Patrn Iterator

    .. iterator - github shichuan

    El objetivo de este patrn es el de encapsular la lgica para recorrer los datos de un objetoEn el patron Iterator nuestro objeto necesita proporcionar un metodo next() que nos devuelva elsiguiente elemento de la secuencia

  • Patrones de Diseo 61

    Tambien se suele proporcionar en este objeto el mtodo hasNext() para verificar si hemos llegadoal final de la secuencia de datos

    1 var agg = (function () {2 var index = 0,3 data = [1, 2, 3, 4, 5],4 length = data.length;56 return {7 next: function () {8 var element;9 if (!this.hasNext()) {10 return null;11 }12 element = data[index];13 index = index + 2;14 return element15 },16 hasNext: function () {17 return index < length;18 }19 };20 }());2122 // this loop logs 1, then 3, then 523 while (agg.hasNext()) {24 console.log(agg.next());25 }

    11.4 Patrn Mixins[estructura, subclassing, code reuse]

    .. The Mixin Pattern | Addy Osmani

    Los Mixins son una manera de recolectar funcionalidades a traves de las extensionesLos Mixins los podemos considerar objetos cuyos atributos y metodos pueden ser compartidospor otros objetos prototipos.

  • Patrones de Diseo 62

    1 var myMixins = {2 moveUp: function(){3 console.log( "move up" );4 },5 moveDown: function(){6 console.log( "move down" );7 },8 stop: function(){9 console.log( "stop! in the name of love!" );10 }11 };1213 // A skeleton carAnimator constructor14 function carAnimator(){15 this.moveLeft = function(){16 console.log( "move left" );17 };18 }1920 // A skeleton personAnimator constructor21 function personAnimator(){22 this.moveRandomly = function(){ /*..*/ };23 }2425 // Extend both constructors with our Mixin26 _.extend( carAnimator.prototype, myMixins );27 _.extend( personAnimator.prototype, myMixins );2829 // Create a new instance of carAnimator30 var myAnimator = new carAnimator();31 myAnimator.moveLeft();32 myAnimator.moveDown();33 myAnimator.stop();34 // Outputs:35 // move left36 // move down37 // stop! in the name of love!

    11.5 Patrn Decorator[estructura, sub-classing, code re-use]

    .. The Decorator Pattern | Addy Osmani

  • Patrones de Diseo 63

    El patron Decorator se centra en cmo extender las funcionalidades de los objetosCon el patrn Decorator podemos aadir/sobreescribir dinamicamente comportamiento a losmtodos existentes de un objetoEjemplo: Decorating Constructors With New Functionality

    1 // A vehicle constructor2 function vehicle( vehicleType ){3 // some sane defaults4 this.vehicleType = vehicleType || "car";5 this.model = "default";6 this.license = "00000-000";7 }89 // Test instance for a basic vehicle10 var testInstance = new vehicle( "car" );11 console.log( testInstance );12 // Outputs:13 // vehicle: car, model:default, license: 00000-00014 // Lets create a new instance of vehicle, to be decorated15 var truck = new vehicle( "truck" );16 // New functionality we're decorating vehicle with17 truck.setModel = function( modelName ){18 this.model = modelName;19 };20 truck.setColor = function( color ){21 this.color = color;22 };23 // Test the value setters and value assignment works correctly24 truck.setModel( "CAT" );25 truck.setColor( "blue" );26 console.log( truck );27 // Outputs:28 // vehicle:truck, model:CAT, color: blue29 // Demonstrate "vehicle" is still unaltered30 var secondInstance = new vehicle( "car" );31 console.log( secondInstance );32 // Outputs:33 // vehicle: car, model:default, license: 00000-000

    Example 2: Decorating Objects With Multiple Decorators

  • Patrones de Diseo 64

    1 // The constructor to decorate2 function MacBook() {3 this.cost = function () { return 997; };4 this.screenSize = function () { return 11.6; };5 }67 // Decorator 18 function Memory( macbook ) {9 var v = macbook.cost();10 macbook.cost = function() {11 return v + 75;12 };13 }1415 // Decorator 216 function Engraving( macbook ){17 var v = macbook.cost();18 macbook.cost = function(){19 return v + 200;20 };21 }2223 // Decorator 324 function Insurance( macbook ){25 var v = macbook.cost();26 macbook.cost = function(){27 return v + 250;28 };29 }3031 var mb = new MacBook();32 Memory( mb );33 Engraving( mb );34 Insurance( mb );3536 // Outputs: 152237 console.log( mb.cost() );38 // Outputs: 11.639 console.log( mb.screenSize() );

    11.6 Patrn FaadeEl objetivo del patron Faade es simplificar la interfaz (los metodos/propiedades pblicos)ocultando el cdigo complejo. Tambien se utiliza para desacoplar nuestro cdigo de las APIsde librerias externas

  • Patrones de Diseo 65

    1 var addMyEvent = function( el,ev,fn ){2 if( el.addEventListener ){3 el.addEventListener( ev,fn, false );4 }else if(el.attachEvent){5 el.attachEvent( "on" + ev, fn );6 } else{7 el["on" + ev] = fn;8 }9 };

    1 var module = (function() {2 var _private = {3 i:5,4 get : function() {5 console.log( "current value:" + this.i);6 },7 set : function( val ) {8 this.i = val;9 },10 run : function() {11 console.log( "running" );12 },13 jump: function(){14 console.log( "jumping" );15 }16 };17 return {18 facade : function( args ) {19 _private.set(args.val);20 _private.get();21 if ( args.run ) {22 _private.run();23 }24 }25 };26 }());2728 // Outputs: "running", 1029 module.facade( {run: true, val:10} );

    11.7 Patrn Observer Subscriber/Publisher

  • Patrones de Diseo 66

    ..

    The Observer Pattern | Addy Osmani Observer | jspatterns.com

    El principal objetivo de este patrn es el de desacoplar las partes de un cdigo.En vez de tener un objeto llamando al mtodo de otro objeto, con este patron un objeto sesubscribe a la actividad de otro objeto y recibe una notificacin cuando esta actividad se produce.1 Subscriber = Observer2 Publisher = Subject

    1 var publisher = {2 subscribers: {3 any: [] // event type: subscribers4 },5 subscribe: function (fn, type) {6 type = type || 'any';7 if (typeof this.subscribers[type] === "undefined") {8 this.subscribers[type] = [];9 }10 this.subscribers[type].push(fn);11 },12 unsubscribe: function (fn, type) {13 this.visitSubscribers('unsubscribe', fn, type);14 },15 publish: function (publication, type) {16 this.visitSubscribers('publish', publication, type);17 },18 visitSubscribers: function (action, arg, type) {19 var pubtype = type || 'any',20 subscribers = this.subscribers[pubtype],21 i,22 max = subscribers.length;23 for (i = 0; i < max; i += 1) {24 if (action === 'publish') {25 subscribers[i](arg);26 } else {27 if (subscribers[i] === arg) {28 subscribers.splice(i, 1);29 }30 }31 }32 }33 };

  • Patrones de Diseo 67

    1 var s1 = {log: console.log},2 s2 = {err: console.error},3 s3 = {warn: console.warn};45 publisher.subscribe(s1.log);6 publisher.subscribe(s2.err);7 publisher.subscribe(s3.warn);8 publisher.publish({hello: "World"});9 publisher.unsubscribe(s2.err);10 publisher.publish("hello");11 publisher.subscribe(s1.log, "log");12 publisher.publish({obj: "log this object"}, "log");

    1 function makePublisher(o) {2 var i;3 for (i in publisher) {4 if (publisher.hasOwnProperty(i) && typeof publisher[i] === "function"\5 ) {6 o[i] = publisher[i];7 }8 }9 o.subscribers = {any: []};10 }1112 var paper = {13 daily: function () {14 this.publish("big news today");15 },16 monthly: function () {17 this.publish("interesting analysis", "monthly");18 }19 };2021 makePublisher(paper);22 var joe = {23 drinkCoffee: function (paper) {24 console.log('Just read ' + paper);25 },26 sundayPreNap: function (monthly) {27 console.log('About to fall asleep reading this ' + monthly);28 }29 };3031 paper.subscribe(joe.drinkCoffee);32 paper.subscribe(joe.sundayPreNap, 'monthly');

  • Patrones de Diseo 68

    33 paper.daily();34 paper.daily();35 paper.daily();36 paper.monthly();37 makePublisher(joe);3839 joe.tweet = function (msg) {40 this.publish(msg);41 };42 paper.readTweets = function (tweet) {43 alert('Call big meeting! Someone ' + tweet);44 };4546 joe.subscribe(paper.readTweets);47 joe.tweet("hated the paper today");

    11.8 Patrn Mediator

    ..

    The Mediator Pattern | Addy Osmani mediator | github shichuan

    El patrnMediator es un patrn de comportamiento que nos permite utilizar una unica interfaza traves de la cual se pueden comunciar las diferentes partes de un sistema (ej. torre controlaeropuerto)En Javascript este patron se suele implementar como un objeto compartido a traves del cual losotros objetos (modulos) de nuestro sistema se pueden comunicar (patron Observer centralizado)

    1 var mediator = (function(){23 // Storage for topics that can be broadcast or listened to4 var topics = {};56 // Subscribe to a topic, supply a callback to be executed7 // when that topic is broadcast to8 var subscribe = function( topic, fn ){9 if ( !topics[topic] ){10 topics[topic] = [];11 }12 topics[topic].push( { context: this, callback: fn } );13 return this;14 };15

  • Patrones de Diseo 69

    16 // Publish/broadcast an event to the rest of the application17 var publish = function( topic ){18 var args;19 if ( !topics[topic] ){20 return false;21 }22 args = Array.prototype.slice.call( arguments, 1 );23 for ( var i = 0, l = topics[topic].length; i < l; i++ ) {24 var subscription = topics[topic][i];25 subscription.callback.apply( subscription.context, args );26 }27 return this;28 };2930 return {31 Publish: publish,32 Subscribe: subscribe,33 installTo: function( obj ){34 obj.subscribe = subscribe;35 obj.publish = publish;36 }37 };3839 }());

  • 12. Unit Testings en Javascript

    ..

    Desarrollo guiado por pruebas | wikipedia.org Introduction To JavaScript Unit Testing |Smashing Magazine

    12.1 Unit Testings (pruebas unitarias)UnUnit testing es un trozo de cdigo que sirve para comprobar que otro trozo de cdigo funcionacorrectamente. Es cdigo que sirve para testear otro cdigo.Estas pruebas unitarias (unit testings) deben:

    ser poder lanzadas de forma automtica (esto es especialmente importante para unaintegracin continua)

    testear la mayor cantidad de cdigo posible (cobertura de cdigo ms alta posible) ser poder ejecutadas infinidad de veces ser independientes, la ejecucin de una prueba no debe afectar a la ejecucin de otra. mantener la calidad de cdigo (convencin de cdigo, buenas practicas, documentacin,)

    Conforme va creciendo el cdigo fuente de un proyecto se va haciendo ms importante el podercomprobar de una manera sencilla que los cambios y el nuevo cdigo no rompen nada del cdigoexistenteEn el caso de Javascript esto es ms importante, porque teniendo los tests podremos comprobarautomaticamente que nuestro cdigo funciona bien en diferentes entornos (IE, Firefox, Chro-me,)

    El unit (La unidad a testear)En TDD, la unidad (el unit) es el trozo ms pequeo de cdigo que puede ser testeado. En lamayoria de los casos se corresponde con una funcin/mtodo.El test suele ser tambien un mtodo/funcin asi que un test unitario sencillo suele ser un metdo(test) que testea otro metodo (unit)A veces se escriben varios unit tests para el mismo mtodo/objeto de manera que cada uno testeaun comportamiento especfico. Estos tests que testean un conjunto de cdigo relacionado (comoun objeto con diferentes mtodos) se suelen agrupar en un test caseLos test cases se suelen agrupar a su vez en test suites

    70

  • Unit Testings en Javascript 71

    Code coverage (Cobertura de cdigo)El code coverage es una forma de medir que proporcin del cdigo fuente est siendo realmentetesteanda por una test suiteLa cobertura del cdigo se suele medir utilizando software que analiza el cdigo y los tests. ParaPHP se suele utilizar PHPUnit con XDebug. Para JS, podemos utilizar Sonar con jsTestDriver

    Mi primer Unit TestingEste es el cdigo a testear (el unit)

    1 function add(a, b) {2 return a + b;3 }

    Y este el cdigo con el que lo testeamos (el testing)

    1 // Test function2 if (add(1, 2) !== 3) {3 document.write('add(1, 2) does not add up to 3');5 } else {6 document.write('add(1, 2) OK');7 }89 if (add("2", 2) !== 4) {10 var msg = "Numbers as strings don't add";11 document.write('' + msg + '');12 } else {13 document.write('add("2", 2) OK');14 }

    Este test lo podemos ejecutar desde aquiEste ejemplo es muy sencillo pero ilustra varias cosas sobre los unit testings:

    La funcin se testea desde varios angulos (se comprueba que devuelve la funcin al pasarlediferentes tipos de datos)

    Comparamos el valor devuelto con un valor esperado Si estos valores coinciden mostramos un OK verde Si estos valores no coinciden mostramos un mensaje de error que nos ayude a localizar elproblema

    El ejemplo anterior no pasaba todos los tests, pero si mejoramos el cdigo

  • Unit Testings en Javascript 72

    1 function add(a, b) {2 return parseInt(a) + parseInt(b);3 }

    Este nuevo cdigo si que pasa los tests, es decir, que cumple con los criterios especificados en eltest

    12.2 TDD y BDD

    Test Driven Development (TDD) TDD (Test Driven Development) es una metodologa, forma de programar, un workflow, quebasicamente consiste en hacer primero los tests (especificando lo que debe hacer nuestro cdigo)y despues hacer el cdigo que pase estos tests.El workflow recomendado de TDD es el siguiente:

    1. Escribimos los tests para una nueva funcionalidad (asumiendo nombres de metodos,parametros de entrada, valores devueltos)

    2. Ejecutamos los tests y comprobamos que fallan (aun no hemos escrito el codigo a testear)3. Escribimos la solucin ms simple que cumpla con los tests4. Refactorizamos el cdigo (cdigo ms limpio y eficiente y que siga pasando los tests)5. Repetimos estos pasos con otra funcionalidad

    Aplicando TDD a la hora de programar nos permite centrarnos en la interfaz (API, methods,inputs & outputs) ms que en los detalles de la implementacin

    Behavior Driven Development (BDD) BDD (Behavior Driven Development) es una versin especializada de TDD que se focalizaen testear (especificaciones de) comportamientos de un softwareUtiliza un lenguaje ms humano para escribir los tests y no se centra tanto en describir comodebe funcionar la API sino en describir que una funcionalidad concreta haga lo que se espera deella

    12.3 Testing Frameworks

    .. Looking for a better JavaScript unit test tool | stackoverflow.com

    Existen unos cuantos Frameworks que nos facilitan la tarea de realizar los tests a nuestro cdigo.Estos frameworks ofrecen un numero determinado de assertions (afirmaciones) con los quepodremos escribir los tests

  • Unit Testings en Javascript 73

    jsTestDriverjsTestDriver es un framework y servidor de tests escrito en Java y que nos permite ejecutar lostests en diferentes maquinas, diferentes sistemas operativos y diferentes browsers a la vezAlgunos assertions:

    assert([msg], actual)assertTrue([msg], actual)Fails if the result isnt truthy. To use a message when fails, add it as the first parameter.

    assertFalse([msg], actual)Fails if the result isnt falsy.

    assertEquals([msg], expected, actual)Fails if the expected and actual values can not be compared to be equal.

    assertNotEquals([msg], expected, actual)Fails if the expected and actual values can be compared to be equal.

    assertNull([msg], actual)_Fails if the given value is not exactly null.

    assertUndefined([msg], actual)Fails if the given value is not undefined.

    assertNotUndefined([msg], actual)Fails if the given value is undefined.

    assertArray([msg], actual)Fails if the given value is not an Array.

    assertFunction([msg], actual)Fails if the given value is not a Function. Convenience function to assertTypeOf.

    assertObject([msg], actual)Fails if the given value is not an Object. Convenience function to assertTypeOf.

    assertNumber([msg], actual)Fails if the given value is not a Number. Convenience function to assertTypeOf.

    assertString([msg], actual)Fails if the given value is not a String. Convenience function to assertTypeOf.

    assertElementId([msg], id, element)Fails if the given DOM element does not have given ID.

    Para este trozo de cdigo:

    1 myapp = {};23 myapp.Greeter = function() { };45 myapp.Greeter.prototype.greet = function(name) {6 return "Hello " + name + "!";7 };

    Un Unit Testing en jsTestDriver podria ser:

  • Unit Testings en Javascript 74

    1 GreeterTest = TestCase("GreeterTest");23 GreeterTest.prototype.testGreet = function() {4 var greeter = new myapp.Greeter();5 assertEquals("Hello World!", greeter.greet("World"));6 };

    ..

    JavaScript Testing with JSTestDriver | meri-stuff.blogspot.com.es GettingStarted w/ JSTest Driver| code.google.comTestCase w/ JS Test Driver| code.google.comAssertions w/JS Test Driver| code.google.com

    QUnitQUnit es un framework de unit testing (para cliente) que nos permite testear nuestro codigoJavascript de una manera sencilla.Es el que se utiliza para los proyectos jQuery, jQuery UI, jQuery Mobile y el propio QUnitAlgunos assertions:

    ok( state, message )A boolean assertion, equivalent to CommonJSs assert.ok() and JUnits assertTrue(). Passesif the first argument is truthy.

    1 // Let's test this function2 function isEven(val) {3 return val % 2 === 0;4 }5 test('isEven()', function() {6 ok(isEven(0), 'Zero is an even number');7 ok(isEven(2), 'So is two');8 ok(isEven(-4), 'So is negative four');9 ok(!isEven(1), 'One is not an even number');10 ok(!isEven(-7), 'Neither is negative seven');11 })

    equal( actual, expected, message )A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.

  • Unit Testings en Javascript 75

    1 test( "equal test", function() {2 equal( 0, 0, "Zero; equal succeeds" );3 equal( "", 0, "Empty, Zero; equal succeeds" );4 equal( "", "", "Empty, Empty; equal succeeds" );5 equal( 0, 0, "Zero, Zero; equal succeeds" );67 equal( "three", 3, "Three, 3; equal fails" );8 equal( null, false, "null, false; equal fails" );9 });

    strictEqual( actual, expected, message )A strict type and value comparison assertion.

    1 test( "strictEqual test", function() {2 strictEqual( 1, 1, "1 and 1 are the same value and type" );3 });

    Para este trozo de cdigo:

    1 // your applications custom code2 function addValues( a, b ) {3 return a + b;4 };

    Un Unit Testing en QUnit podria ser:

    1 // the QUnit test code2 test("test addValues(a, b) function", function() {3 equal(addValues( 1, 2), 3, "1 + 2 = 3" );4 equal(addValues( 1.75, 2), 3.75, "1.75 + 2 = 3.75" );5 notEqual(addValues( 1, 2), "3", "1 + 2 != '3' as a String");6 });

    ..

    How to Test your JavaScript CodewithQUnit | code.tutsplus.comAsserts | api.qunitjs.comCookbook | qunitjs.comQUnit, testeando nuestras aplicaciones Javascript | etnassoft.com Getting Started With jQuery QUnit for Client-Side Javascript Testing | lostechies.com

  • Unit Testings en Javascript 76

    JasmineJasmine es un framework para testear cdigo Javascript orientado a BDD (testar funcionalidades),pero se puede utilizar tambin para TDD (testear API).Un test suite en Jasmine se declara con la funcin global describe que recibe:

    el nombre de la suite una funcin con el cdigo que implementa los tests

    Las specs se declaran con la funcin global it que recibe:

    una descripcin de la especificacin una funcin con una o ms expectations

    Los expectations (comportamientos esperados) se deescriben con las funcin expect y unmatcher (toBe, toEqual, ):

    1 describe("A suite", function() {2 it("contains spec with an expectation", function() {3 expect(true).toBe(true);4 });5 });

    Algunos matchers que ofrece Jasmine por defecto (podemos construirnos los nuestros propios)

    expect(x).toEqual(y);compares objects or primitives x and y and passes if they are equivalent

    expect(x).toBe(y);compares objects or primitives x and y and passes if they are the same object

    expect(x).toMatch(pattern);compares x to string or regular expression pattern and passes if they match

    expect(x).toBeDefined();passes if x is not undefined

    expect(x).toBeUndefined();passes if x is undefined

    expect(x).toBeNull();passes if x is null

    expect(x).toBeTruthy();passes if x evaluates to true

    expect(x).toBeFalsy();passes if x evaluates to false

    expect(x).toContain(y);passes if array or string x contains y

  • Unit Testings en Javascript 77

    expect(x).toBeLessThan(y);passes if x is less than y

    expect(x).toBeGreaterThan(y);passes if x is greater than y

    expect(function(){fn();}).toThrow(e);passes if function fn throws exception e when executed

    Para este trozo de cdigo:

    1 // your applications custom code2 function addValues( a, b ) {3 return a + b;4 };

    Un Unit Testing en Jasmine podria ser:

    1 // the Jasmine test code2 describe("addValues(a, b) function", function() {3 it("should equal 3", function(){4 expect( addValues(1, 2) ).toBe( 3 );5 });6 it("should equal 3.75", function(){7 expect( addValues(1.