Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
wiki2:js [2017/05/12 11:13] alfred [Lambdas] |
wiki2:js [2022/11/03 16:21] (actual) |
||
|---|---|---|---|
| Línea 335: | Línea 335: | ||
| </code> | </code> | ||
| Calling .then produces a new promise, whose result depends on the return value of the first function we passed to then | Calling .then produces a new promise, whose result depends on the return value of the first function we passed to then | ||
| + | |||
| + | You can also wait for all promises: | ||
| + | <code> | ||
| + | var p1 = Promise.resolve(3); | ||
| + | var p2 = 1337; | ||
| + | var p3 = new Promise((resolve, reject) => { | ||
| + | setTimeout(resolve, 100, 'foo'); | ||
| + | }); | ||
| + | |||
| + | Promise.all([p1, p2, p3]).then(values => { | ||
| + | console.log(values); // [3, 1337, "foo"] | ||
| + | }); | ||
| + | </code> | ||
| + | How ''reject'' is managed: | ||
| + | <code> | ||
| + | var p1 = new Promise((resolve, reject) => { | ||
| + | setTimeout(resolve, 1000, 'one'); | ||
| + | }); | ||
| + | var p2 = new Promise((resolve, reject) => { | ||
| + | setTimeout(resolve, 2000, 'two'); | ||
| + | }); | ||
| + | var p3 = new Promise((resolve, reject) => { | ||
| + | setTimeout(resolve, 3000, 'three'); | ||
| + | }); | ||
| + | var p4 = new Promise((resolve, reject) => { | ||
| + | setTimeout(resolve, 4000, 'four'); | ||
| + | }); | ||
| + | var p5 = new Promise((resolve, reject) => { | ||
| + | reject('reject'); | ||
| + | }); | ||
| + | |||
| + | Promise.all([p1, p2, p3, p4, p5]).then(values => { | ||
| + | console.log(values); | ||
| + | }).catch(reason => { | ||
| + | console.log(reason) | ||
| + | }); | ||
| + | |||
| + | //From console: | ||
| + | //"reject" | ||
| + | </code> | ||
| + | ===== Modules ===== | ||
| + | Immediately-Invoked Function Expression (IIFE) is a anonymous function which invokes itself. | ||
| + | <code> | ||
| + | //Module Starts | ||
| + | |||
| + | (function(window){ | ||
| + | |||
| + | var sum = function(x, y){ | ||
| + | return x + y; | ||
| + | } | ||
| + | |||
| + | var sub = function(x, y){ | ||
| + | return x - y; | ||
| + | } | ||
| + | |||
| + | var math = { | ||
| + | findSum: function(a, b){ | ||
| + | return sum(a,b); | ||
| + | }, | ||
| + | |||
| + | findSub: function(a, b){ | ||
| + | return sub(a, b); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | window.math = math; | ||
| + | |||
| + | })(window); | ||
| + | |||
| + | //Module Ends | ||
| + | |||
| + | |||
| + | console.log(math.findSum(1, 2)); //3 | ||
| + | console.log(math.findSub(1, 2)); //-1 | ||
| + | </code> | ||
| + | Here sum and sub function objects remain in memory but there is no way the program which uses the module can access them therefore we prevented any chances of overriding global variables. The only thing thats available global is math object which exposes all the functionality of the module by hiding their implementation. | ||
| + | |||
| + | ==== CommonJS ==== | ||
| + | CommonJS is a **non-browser JavaScript** specification for creating modules. | ||
| + | |||
| + | Suppose we have two files “main.js” and “math.js”. Here is the code in “math.js” file | ||
| + | <code> | ||
| + | var sum = function(x, y){ | ||
| + | return x + y; | ||
| + | } | ||
| + | |||
| + | var sub = function(x, y){ | ||
| + | return x - y; | ||
| + | } | ||
| + | |||
| + | var math = { | ||
| + | findSum: function(a, b){ | ||
| + | return sum(a,b); | ||
| + | }, | ||
| + | |||
| + | findSub: function(a, b){ | ||
| + | return sub(a, b); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | //All the variable we want to expose outside needs to be property of "exports" object. | ||
| + | exports.math = math; | ||
| + | </code> | ||
| + | Here is the code in “main.js” file | ||
| + | <code> | ||
| + | //no file extension required | ||
| + | var math = require("./math").math; | ||
| + | console.log(math.findSum(1, 2)); //3 | ||
| + | console.log(math.findSub(1, 2)); //-1 | ||
| + | </code> | ||
| + | |||
| + | ==== Asynchronous Module Definition (AMD) ==== | ||
| + | AMD is a JavaScript browser specification for creating modules. One such AMD library is RequireJS. | ||
| + | |||
| + | ==== Universal Module Definition ==== | ||
| + | UMD is a set of techniques to create modules that can be imported using CommonJS, AMD or as IIFE. UMD modules are called Universal Modules. There are many techniques under UMD. Its upto you to choose whichever you want to use for creating modules. My favourite UMD technique is returnExports. | ||
| ===== ECMAScript 6 (ES6) ===== | ===== ECMAScript 6 (ES6) ===== | ||
| Línea 404: | Línea 520: | ||
| + | ==== Template Strings ==== | ||
| + | <code> | ||
| + | var a = 5; | ||
| + | var b = 10; | ||
| + | console.log(`Fifteen is ${a + b} and | ||
| + | not ${2 * a + b}.`); | ||
| + | // "Fifteen is 15 and | ||
| + | // not 20." | ||
| + | </code> | ||
| + | <code> | ||
| + | var str = String.raw`Hi\n${2+3}!`; | ||
| + | // "Hi\n5!" | ||
| + | </code> | ||
| + | |||
| + | <code> | ||
| + | // Simple string substitution | ||
| + | var name = "Brendan"; | ||
| + | console.log(`Yo, ${name}!`); | ||
| + | // => "Yo, Brendan!" | ||
| + | </code> | ||
| + | |||
| + | <code> | ||
| + | var greeting = "Yo \ | ||
| + | World"; | ||
| + | |||
| + | console.log(`string text line 1 | ||
| + | string text line 2`); | ||
| + | </code> | ||
| + | ==== ES6 Modules ==== | ||
| + | <code> | ||
| + | export class Math { | ||
| + | |||
| + | constructor() | ||
| + | { | ||
| + | this.sum = function(x, y){ | ||
| + | return x + y; | ||
| + | } | ||
| + | |||
| + | this.sub = function(x, y){ | ||
| + | return x - y; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | findSum(a, b) | ||
| + | { | ||
| + | return this.sum(a, b); | ||
| + | } | ||
| + | |||
| + | findSub(a, b) | ||
| + | { | ||
| + | return this.sub(a, b); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <code> | ||
| + | import {Math} from 'math'; | ||
| + | |||
| + | var math = new Math(); | ||
| + | |||
| + | console.log(math.findSum(1, 2)); //3 | ||
| + | console.log(math.findSub(1, 2)); //-1 | ||
| + | </code> | ||
| + | ==== The ...args operator (spread operator) ==== | ||
| + | |||
| + | <code> | ||
| + | //args variable is an array holding the passed function arguments | ||
| + | function function_one(...args) | ||
| + | { | ||
| + | console.log(args); | ||
| + | console.log(args.length); | ||
| + | } | ||
| + | |||
| + | function_one(1, 4); | ||
| + | function_one(1, 4, 7); | ||
| + | function_one(1, 4, 7, 0); | ||
| + | |||
| + | |||
| + | function function_two(a, b, ...args) | ||
| + | { | ||
| + | console.log(args); | ||
| + | console.log(args.length); | ||
| + | } | ||
| + | |||
| + | //"args" holds only 7 and 9 | ||
| + | function_two(1, 5, 7, 9); | ||
| + | </code> | ||
| + | |||
| + | <code> | ||
| + | //args variable is an array holding the function arguments | ||
| + | function function_one() | ||
| + | { | ||
| + | var args = Array.prototype.slice.call(arguments, function_one.length); | ||
| + | |||
| + | console.log(args); | ||
| + | console.log(args.length); | ||
| + | } | ||
| + | |||
| + | function_one(1, 4); | ||
| + | function_one(1, 4, 7); | ||
| + | function_one(1, 4, 7, 0); | ||
| + | |||
| + | |||
| + | function function_two(a, b) | ||
| + | { | ||
| + | var args = Array.prototype.slice.call(arguments, function_two.length); | ||
| + | |||
| + | console.log(args); | ||
| + | console.log(args.length); | ||
| + | } | ||
| + | |||
| + | //"args" holds only 7 and 9 | ||
| + | function_two(1, 5, 7, 9); | ||
| + | </code> | ||
| + | |||
| + | <code> | ||
| + | function function_name(a, b) | ||
| + | { | ||
| + | console.log(a+b); | ||
| + | } | ||
| + | |||
| + | var array = [1, 4]; | ||
| + | |||
| + | function_name(...array); //is equal to function_name(1, 4) | ||
| + | </code> | ||
| ==== for loop ==== | ==== for loop ==== | ||
| <code> | <code> | ||
| Línea 667: | Línea 908: | ||
| map_1.get(4); | map_1.get(4); | ||
| + | </code> | ||
| + | |||
| + | |||
| + | |||
| + | ===== Javascript Snippets ===== | ||
| + | |||
| + | |||
| + | ==== Merge two objects ==== | ||
| + | <code> | ||
| + | Object.assign(obj1, obj2); | ||
| + | let newObject = Object.assign({}, obj1, obj2, obj3, etc); | ||
| + | </code> | ||
| + | |||
| + | |||
| + | ==== URL parameters ====== | ||
| + | <code> | ||
| + | var urlParams = new URLSearchParams(window.location.search); | ||
| + | |||
| + | console.log(urlParams.has('post')); // true | ||
| + | console.log(urlParams.get('action')); // "edit" | ||
| + | console.log(urlParams.getAll('action')); // ["edit"] | ||
| + | console.log(urlParams.toString()); // "?post=1234&action=edit" | ||
| + | console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1" | ||
| + | </code> | ||
| + | |||
| + | ==== Local Storage ==== | ||
| + | |||
| + | <code> | ||
| + | window.localStorage.setItem('test', 'hola'); | ||
| + | </code> | ||
| + | |||
| + | * setItem(): Add key and value to localStorage | ||
| + | * getItem(): Retrieve a value by the key from localStorage | ||
| + | * removeItem(): Remove an item by key from localStorage | ||
| + | * clear(): Clear all localStorage | ||
| + | * key(): Passed a number to retrieve nth key of a localStorage | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== JavaScript Notes ===== | ||
| + | <code> | ||
| + | > b = a.c || 4; | ||
| + | 4 | ||
| + | </code> | ||
| + | |||
| + | ==== ES6 Events ==== | ||
| + | <code> | ||
| + | const EventEmitter = require('events'); | ||
| + | |||
| + | class Client extends EventEmitter | ||
| + | { | ||
| + | eventTest() { | ||
| + | this.emit('event'); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | let testClient = new Client(1,2,3,4,5); | ||
| + | testClient.once('event', () => {console.log('triggerd1!')} ); | ||
| + | testClient.on('event', () => {console.log('triggerd2!')} ); | ||
| + | testClient.eventTest(); | ||
| + | testClient.eventTest(); | ||
| + | </code> | ||
| + | |||
| + | ==== ES6 Events to Promises ==== | ||
| + | pues es tema de que se encolan los errores. Es decir, pongamos que tengo varias promises, una para (yo que sé) login, logout, cookies. Todas con su then y catch. De repente hay un error en logout, se lanzarán todos los errores (login, logout y cookies). Aún peor, si pongo un if en logout para recibir "error de logout" el evento se recibirá en todos, pero ya no se volverá a recibir en logout. La coña de las promises es que una vez se lancen no lo vuelven a hacer, he de hacer un control muy bestia de errores (no me vale pillar el evento con once). | ||
| + | <code> | ||
| + | const EventEmitter = require('events'); | ||
| + | |||
| + | class Client extends EventEmitter | ||
| + | { | ||
| + | constructor() { | ||
| + | super(); | ||
| + | this.num = 0; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class Wrapper | ||
| + | { | ||
| + | constructor (tclient) { | ||
| + | this.client = tclient; | ||
| + | } | ||
| + | |||
| + | login() { | ||
| + | return new Promise(function (resolve, reject) { | ||
| + | this.client.on('login', () => { | ||
| + | console.log("received event login"); | ||
| + | resolve(); | ||
| + | }); | ||
| + | this.client.on('eerror', (error) => { | ||
| + | if (error === "login error") reject(error); | ||
| + | }); | ||
| + | }.bind(this)); | ||
| + | } | ||
| + | |||
| + | logout() { | ||
| + | return new Promise(function (resolve, reject) { | ||
| + | this.client.on('logout', () => { | ||
| + | console.log("received event logout"); | ||
| + | resolve(); | ||
| + | }); | ||
| + | this.client.on('eerror', (error) => { | ||
| + | if (error === "logout error") reject(error); | ||
| + | }); | ||
| + | }.bind(this)); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | let client = new Client(); | ||
| + | let wrapper = new Wrapper(client); | ||
| + | |||
| + | var p1 = wrapper.login().then(function() { | ||
| + | console.log("login"); | ||
| + | }).catch(function(error) { | ||
| + | console.error("Reception error login"); | ||
| + | }); | ||
| + | |||
| + | var p2 = wrapper.logout().then(function() { | ||
| + | console.log("logout"); | ||
| + | }).catch(function(error) { | ||
| + | console.error("Reception error logout"); | ||
| + | }); | ||
| + | |||
| + | |||
| + | setTimeout(function() { | ||
| + | client.emit('eerror', 'login error'); | ||
| + | client.emit('logout'); | ||
| + | client.emit('logout'); | ||
| + | client.emit('logout'); | ||
| + | client.emit('eerror', 'logout error'); | ||
| + | }, 1000 * 1); | ||
| + | </code> | ||
| + | |||
| + | ==== JQuery (again) ==== | ||
| + | |||
| + | <code> | ||
| + | <a href="#" class="deleteUser" data-id="33" /> | ||
| + | |||
| + | // Now we can take it with JQuery like this: | ||
| + | $('.deleteUser').on('click', function() { | ||
| + | $(this).data('id') | ||
| + | }); | ||
| + | </code> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== JavaScript Development Tools ==== | ||
| + | === Webpack === | ||
| + | |||
| + | * https://youtu.be/GU-2T7k9NfI | ||
| + | |||
| + | ''webpack src/js/app.js dist/bundle.js'' es el comando básico, una vez añadido webpack, para generar un bundle.js. Webpack puede realizar otras tareas de optimización y minimización si añadimos que es para producción con ''-p''. | ||
| + | |||
| + | Lo que hace es pillar a partir de los imports dentro del código js qué construir. Módulos y plugins que utiliza Webpack para CSS también requieren que incluyas ficheros .css en el código js. | ||
| + | |||
| + | Añadiendo **webpack-dev-server** como pacate al proyecto y substituyendo el comando de ejecución ''webpack'' por ''webpack-dev-server'' se nos añade un dev web server que nos permite hacer reload de los ficheros y demás. El comando sería: ''webpack-dev-server --entry ./src/js/apps.js ---output ./dist/bundle.js''. | ||
| + | |||
| + | == Configuración == | ||
| + | |||
| + | Webpack necesita un entry point y un output. Usa modulos y plugins para transformar el contenido desde el entry al output. | ||
| + | |||
| + | Para escoger un fichero config (diferente al por defecto: ''webpack.config.js'') se puede añadir ''--config'' al comando. Con un archivo por defecto no necesitamos añadir parámetros al comando de ejecución. | ||
| + | |||
| + | <code> | ||
| + | var path = require('path'); | ||
| + | |||
| + | module.exports = { | ||
| + | entry: './src/js/app.js', | ||
| + | output: { | ||
| + | path: path.resolve(__dirname, 'dist'), | ||
| + | filename: 'bundle.js', | ||
| + | publicPath: '/dist' // Para el webpack-dev-server, donde encontrar los ficheros | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | == Modulos == | ||
| + | |||
| + | Tras el output podemos añadir una sección de ''modules''. Modules tiene un array de ''rules'' que es sobre qué elementos se aplica un módulo. Un módulo es un transformador del código y lo has de instalar previamente (''npm install css-loader style-loader --save-dev''). | ||
| + | |||
| + | Las reglas (rules) son un array de objetos js con varias propiedades. La primera es una expresión regular correspondiente a los nombres de ficheros, ''test'', si se valida se ejecutará una serie de "comandos" dentro del array de ''use''. | ||
| + | |||
| + | ===== More JavaScript ===== | ||
| + | ==== Default arguments on functions ==== | ||
| + | <code javascript> | ||
| + | const defaultPerson = { | ||
| + | name: { | ||
| + | first: "Shane", | ||
| + | last: "McConkey" | ||
| + | }, | ||
| + | favActivity: "skiing"}; | ||
| + | function logActivity(person = defaultPerson) { | ||
| + | console.log(`${person.name.first} loves ${person.favActivity}`); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Arrow functions ==== | ||
| + | This: | ||
| + | <code javascript> | ||
| + | const lordify = function(firstName) { | ||
| + | return `${firstName} of Canterbury`; | ||
| + | }; | ||
| + | </code> | ||
| + | Is the same than this: | ||
| + | <code javascript> | ||
| + | const lordify = firstName => `${firstName} of Canterbury`; | ||
| + | </code> | ||
| + | Arrow functions protect the scope of this. | ||
| + | |||
| + | For example this fails: | ||
| + | <code javascript> | ||
| + | const tahoe = { | ||
| + | mountains: ["Freel", "Rose", "Tallac", "Rubicon", "Silver"], | ||
| + | print: function(delay = 1000) { | ||
| + | console.log(this); // Window {} | ||
| + | setTimeout(function() { | ||
| + | console.log(this.mountains.join(", ")); | ||
| + | }, delay); | ||
| + | }}; | ||
| + | tahoe.print(); // Uncaught TypeError: Cannot read property 'join' of undefined | ||
| + | </code> | ||
| + | But this not: | ||
| + | <code javascript> | ||
| + | const tahoe = { | ||
| + | mountains: ["Freel", "Rose", "Tallac", "Rubicon", "Silver"], | ||
| + | print: function(delay = 1000) { | ||
| + | setTimeout(() => { | ||
| + | console.log(this.mountains.join(", ")); | ||
| + | }, delay); | ||
| + | } | ||
| + | }; | ||
| + | tahoe.print(); // Freel, Rose, Tallac, Rubicon, Silver | ||
| </code> | </code> | ||