JavaScript para desarrolladores de C# Edin Kapić
JavaScript != C# Edin Kapić
JavaScript: “With or Without You” Brendan Eich “El padre de la criatura”
¿Cómo llegamos hasta aquí? 1995 Netscape Navigator 2.0 Mocha/LiveScript 1996 Internet Explorer 3.0 JScript 1997 ECMAScript
1999 XMLHttpRequest (OWA Exchange 2000) 2005 Jesse James Garrett AJAX 2006 John Resig jQuery
TypeScript 2009 PhoneGap 2010 Node.js 2011 Windows 8 2012 SharePoint 2013 TypeScript
Hay que saltar de una vez
Las herramientas Firebug / IE Dev Tools JSLint JSHint JsFiddle Firebug Lite Las herramientas https://getfirebug.com/firebug-lite.js
JavaScript es bueno ... Lenguaje dinámico Notación literal potente “Loose-typed” “JS is Lisp in C Clothing” (Douglas Crockford) http://bit.ly/Qn0qLi
... pero tiene cosas malas Variables globales implícitas Variable hoisting Function hoisting Prototype Leaking == '' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true
JavaScript != C#
C# JavaScript Corta el pan Tiene mecanismos de seguridad Es complejo Te puedes hacer daño Es un trozo de metal con un mango
Bueno en C#, malo en JS La sintaxis parecida nos puede llevar a hacer lo que en C# son buenas prácticas ...pero en JS pueden tener consecuencias graves “If it walks like a duck...”
JS != C# 1: Tipos de datos Simples Complejos Number String Boolean Undefined Null Object Array Function RegExp Date Undefined = No sé de que m’estàs parlant o no m’has donat cap valor inicial Null = M’has dit que no té cap valor, explícitament Typeof(null) == object (és un bug de JS) Els wrappers també son objects, però és millor no fer-los servir
JS != C# 2: Variables globales Toda variable no asignada a un objeto, se asigna a window var a = 1; window.a = 1; http://jsfiddle.net/wQDwN/
JS != C# 3: “Variable Hoisting” Sólo dos niveles: global i función { } no crea ámbito de variable (como C#) La variable declarada sube hasta el inicio de la función en la que está declarada /*.....*/ var a = 1; var a; /*.....*/ a = 1; http://jsfiddle.net/NE2Km/3/
Recomendación Ser consciente de los tipos de datos No contaminar window Declarar variables lo más arriba possible (hacer hoisting explícito)
Test var imAGlobal = true; function globalGrabber() { imAGlobal = false; return imAGlobal; } console.log(imAGlobal); console.log(globalGrabber()); console.log(imAGlobal); // true o false?
Test var imAGlobal = true; function globalGrabber() { var imAGlobal = false; return imAGlobal; } console.log(imAGlobal); console.log(globalGrabber()); console.log(imAGlobal); // true o false? http://jsfiddle.net/JxESg/
JS != C# 4: this this apunta al objeto contenedor de la función en la que está (en ejecución) y es modificable console.log(this); // window var myFunction = function() { console.log(this); } myFunction(); // window http://jsfiddle.net/UsCtz/ y http://jsfiddle.net/8tBEM/
JS != C# 5: Wrappers JS estilo C# JS estilo puro var myVar = new Object(); var myArr = new Array(); JS estilo puro var myVar = {}; var myArr = [];
Recomendación No usar wrappers innecesariamente Aprender la notación literal de objetos de JS
Test var a = new Object(); a.nombre = 'Edin'; console.log(a.nombre);
Test var a = { nombre: 'Edin' }; console.log(a.nombre);
Test var a = function() { this.nombre = 'Edin'; return this; }(); console.log(a.nombre);
Test var a = function() { this.nombre = 'Edin'; return this; }(); console.log(a.document.URL);
Test var a = function() { var obj = {}; obj.nombre = 'Edin'; return obj; }(); console.log(a.document.URL);
JS != C# 6: Truthy / Falsey Valores que dan true Valores que dan false "0" "false" Objetos vacíos Todos los demás false "" null undefined NaN
Recomendación Simplificar los condicionales if(myVar != "" || myVar != undefined) if(myVar) Inicializar los valores por defecto if(myVar == "") { myVar = "Hola"; } myVar = myVar || "hola";
JS != C# 7: Operador == Comparación if(false == 0) // true if(false === 0) // false El operador == intenta convertir los valores y casi siempre es algo que no queremos
Comparación “indeterminista” (false == 0); // true (false == ""); // true (0 == ""); // true (null == false); // false (null == null); // true (undefined == undefined); // true (undefined == null); // true (NaN == null); // false (NaN == NaN); // false
Recomendación Usar los operadores === i !== por defecto No hacen la conversión de valores Se comportan como los operadores “habituales” == y != de C#
JS != C# 8: Otras “perlas” parseInt() Operador + http://jsfiddle.net/tbMX2/ NaN http://jsfiddle.net/vVgB9/ “Prototype Leak” Inserción de ; Parseint leading 0 octal
Funciones
Funciones de JavaScript Son objetos, por tanto se les pueden agregar propiedades Se pueden pasar como parámetros a otras funciones Hay dos maneras de declarar funciones
Manera 1: Declaración La declaración de la función se hace con function foo() { /* .... */ } La función declarada hace “hoisting” y està disponible en todo el código JS, independientemente del orden de ejecución Validar amb JSLint per a veure el warning http://jsfiddle.net/TQ6LG/
Manera 2: Expresión También podemos asignar la función a una variable mediante una expresión: var foo = function () { /* ... */ }; En este caso no hay “hoisting” Podemos pensar que una declaración es realmente una expresión puesta al principio http://jsfiddle.net/NrQhM/
Equivalencias function foo() { /* .... */ } var foo = function () { /* ... */ }; var foo = function foo () { /* ... */ }; var foo = function bar () { /* ... */ }; Las dos últimas se usan para funciones recursivas Las expresiones hacen explícita la declaración
Código de un solo uso (IIFE) Podemos asignar una función anónimamente y no recogerla como resultado Útil para ejecutar un código privado y de una sola vez (function () { /* ... */ })(); http://jsfiddle.net/YAe9S/1/
Anidamiento de funciones Las funcions son objetos y pueden contener otras funciones var foo = function() { function bar() { /* ... */ } return bar(); }; foo(); http://jsfiddle.net/XUswD/
Cierres (Closures) El cierre es una manera de asociar la función con sus parámetros de entrada Es el mantenimiento de las variables locales después de que la función haya acabado var bind = function(x) { return function(y) { return x + y; }; } var plus5 = bind(5); alert(plus5(3)); http://jsfiddle.net/xWAm4/
Recomendaciones Dedicar tiempo para jugar con las funciones en JS es imprescindible Hay muchos ejemplos que se pueden probar con JsFiddle Comprender los cierres es importante para entender los event handlers y encapsulamiento (http://jsfiddle.net/GBfPf/)
JavaScript en el siglo XXI
¿Vamos tirando?
¿O estamos al día?
Regla #1: Unobtrusive JavaScript El JS se tieen que añadir sin impactar el HTML de la página <input type="text" name="date“ onchange="validateDate()" /> window.onload = function() { document.getElementById('date').onchange = validateDate; };
Regla #2: Modularidad No colisionar con otros JS presentes (es decir, “comportarnos bien”) Encapsulemos nuestro código en namespaces Usemos try/catch
Métodos de encapsulamiento Ninguno (objeto window) Todo privado (función anónima auto-ejecutada) Todo público (objeto literal) Mezcla público/privado (Revealing Module)
Objeto literal var car = { status: "off", start: function() { this.status = "on"; }, getStatus: function() { return "the car is " + this.status; } }; car.start(); alert(car.getStatus()); http://jsfiddle.net/DY2Zw/
Revealing Module var car = (function() { var pubCar = {}, var innerStatus = "off"; pubCar.start = function() { innerStatus = "on"; } pubCar.status = function() { return "the car is “ + innerStatus; } return pubCar; }()); car.start(); alert(car.status()); http://jsfiddle.net/AUzNT/
Recomendaciones Usar Revealing Module para tenir el encapsulamiento totalmente controlado por nosotros Aislarnos de otras librerías http://jsfiddle.net/uKuLw/ Usar objetos literales para objetos sencillos (p.ej. DTOs) La sintaxis es diferente
Regla #3: Abstracción Nos abstraeremos de los detalles del navegador concreto Existen librerías que unifican y abstraen las diferencias: jQuery, AmplifyJS, Modernizr
Microsoft TypeScript Es un lenguaje basado en JavaScript Añade la comprobación en tiempo de compilación de referencias, tipos, clases e interfaces (Trans)compila a JavaScript “puro” Disponible para VS2012 http://www.typescriptlang.org/
Resumen
Recomendaciones Invertir tiempo en aprender los principios de JS y experimentar con los ejemplos Repasar el código existente con JSHint Tener en cuenta las librerías de JS como factor arquitectónico en las aplicaciones JS está aquí para quedarse
Bibliografia Douglas Crockford “JavaScript: The Good Parts” (O’Reilly) Addy Osmani “JavaScript Design Patterns” http://bit.ly/bMyoQ9 http://jsbooks.revolunet.com/ http://superherojs.com