├── LICENSE ├── es5 └── README.md └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Paolo Carrasco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /es5/README.md: -------------------------------------------------------------------------------- 1 | [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 2 | 3 | [# Airbnb JavaScript Style Guide() {](https://github.com/airbnb/javascript) 4 | 5 | *Un enfoque altamente razonable para JavaScript* 6 | 7 | 8 | ## Tabla de Contenido 9 | 10 | 1. [Tipos](#types) 11 | 1. [Objetos](#objects) 12 | 1. [Arreglos](#arrays) 13 | 1. [Cadenas de Texto](#strings) 14 | 1. [Funciones](#functions) 15 | 1. [Propiedades](#properties) 16 | 1. [Variables](#variables) 17 | 1. [Hoisting](#hoisting) 18 | 1. [Expresiones de comparación e igualdad](#conditionals) 19 | 1. [Bloques](#blocks) 20 | 1. [Comentarios](#comments) 21 | 1. [Espacios en blanco](#whitespace) 22 | 1. [Comas](#commas) 23 | 1. [Puntos y Comas](#semicolons) 24 | 1. [Casting de Tipos & Coerción](#type-coercion) 25 | 1. [Convenciones de nomenclatura](#naming-conventions) 26 | 1. [Funciones de Acceso](#accessors) 27 | 1. [Constructores](#constructors) 28 | 1. [Eventos](#events) 29 | 1. [Módulos](#modules) 30 | 1. [jQuery](#jquery) 31 | 1. [Compatibilidad con ES5](#es5) 32 | 1. [Pruebas](#testing) 33 | 1. [Desempeño](#performance) 34 | 1. [Recursos](#resources) 35 | 1. [En la cancha](#in-the-wild) 36 | 1. [Traducciones](#translation) 37 | 1. [La guía de la Guía del Estilo JavaScript](#guide-guide) 38 | 1. [Colaboradores](#contributors) 39 | 1. [Charla con nosotros sobre Javascript](#chat-with-us-about-javascript) 40 | 1. [Licencia](#license) 41 | 42 | ## Tipos 43 | 44 | - **Primitivos**: Cuando accesas a un tipo primitivo, manejas directamente su valor 45 | 46 | + `string` 47 | + `number` 48 | + `boolean` 49 | + `null` 50 | + `undefined` 51 | 52 | ```javascript 53 | var foo = 1; 54 | var bar = foo; 55 | 56 | bar = 9; 57 | 58 | console.log(foo, bar); // => 1, 9 59 | ``` 60 | - **Complejo**: Cuando accesas a un tipo complejo, manejas la referencia a su valor. 61 | 62 | + `object` 63 | + `array` 64 | + `function` 65 | 66 | ```javascript 67 | var foo = [1, 2]; 68 | var bar = foo; 69 | 70 | bar[0] = 9; 71 | 72 | console.log(foo[0], bar[0]); // => 9, 9 73 | ``` 74 | 75 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 76 | 77 | ## Objetos 78 | 79 | - Usa la sintaxis literal para la creación de un objeto. 80 | 81 | ```javascript 82 | // mal 83 | var item = new Object(); 84 | 85 | // bien 86 | var item = {}; 87 | ``` 88 | 89 | - No uses [palabras reservadas](http://es5.github.io/#x7.6.1) para nombres de propiedades. No funciona en IE8. [Más información](https://github.com/airbnb/javascript/issues/61) 90 | 91 | ```javascript 92 | // mal 93 | var superman = { 94 | default: { clark: 'kent' }, 95 | private: true 96 | }; 97 | 98 | // bien 99 | var superman = { 100 | defaults: { clark: 'kent' }, 101 | hidden: true 102 | }; 103 | ``` 104 | 105 | - Usa sinónimos legibles en lugar de palabras reservadas. 106 | 107 | ```javascript 108 | // mal 109 | var superman = { 110 | class: 'alien' 111 | }; 112 | 113 | // mal 114 | var superman = { 115 | klass: 'alien' 116 | }; 117 | 118 | // bien 119 | var superman = { 120 | type: 'alien' 121 | }; 122 | ``` 123 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 124 | 125 | ## Arreglos 126 | 127 | - Usa la sintaxis literal para la creación de arreglos 128 | 129 | ```javascript 130 | // mal 131 | var items = new Array(); 132 | 133 | // bien 134 | var items = []; 135 | ``` 136 | 137 | - Usa Array#push, en vez de asignación directa, para agregar elementos a un arreglo. 138 | 139 | ```javascript 140 | var someStack = []; 141 | 142 | // mal 143 | someStack[someStack.length] = 'abracadabra'; 144 | 145 | // bien 146 | someStack.push('abracadabra'); 147 | ``` 148 | 149 | - Cuando necesites copiar un arreglo usa Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) 150 | 151 | ```javascript 152 | var len = items.length; 153 | var itemsCopy = []; 154 | var i; 155 | 156 | // mal 157 | for (i = 0; i < len; i++) { 158 | itemsCopy[i] = items[i]; 159 | } 160 | 161 | // bien 162 | itemsCopy = items.slice(); 163 | ``` 164 | 165 | - Para convertir un objeto ["array-like" (similar a un arreglo)](https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-7/array-like-objects) a un arreglo, usa Array#slice. 166 | 167 | ```javascript 168 | function trigger() { 169 | var args = Array.prototype.slice.call(arguments); 170 | ... 171 | } 172 | ``` 173 | 174 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 175 | 176 | 177 | ## Cadenas de Texto 178 | 179 | - Usa comillas simples `''` para las cadenas de texto 180 | 181 | ```javascript 182 | // mal 183 | var name = "Bob Parr"; 184 | 185 | // bien 186 | var name = 'Bob Parr'; 187 | 188 | // mal 189 | var fullName = "Bob " + this.lastName; 190 | 191 | // bien 192 | var fullName = 'Bob ' + this.lastName; 193 | ``` 194 | 195 | - Las cadenas de texto con una longitud mayor a 100 caracteres deben ser escritas en múltiples líneas usando concatenación. 196 | 197 | > **Nota:** Cuando se usa sin criterio, las cadenas de texto largas pueden impactar en el desempeño. [jsPerf](http://jsperf.com/ya-string-concat) & [Discusión](https://github.com/airbnb/javascript/issues/40) 198 | 199 | ```javascript 200 | // mal 201 | var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; 202 | 203 | // bien 204 | var errorMessage = 'This is a super long error that was thrown because\ 205 | of Batman. When you stop to think about how Batman had anything to do \ 206 | with this, you would get nowhere fast.'; 207 | 208 | // bien 209 | var errorMessage = 'This is a super long error that was thrown because' + 210 | 'of Batman. When you stop to think about how Batman had anything to do ' + 211 | 'with this, you would get nowhere fast.'; 212 | ``` 213 | 214 | - Cuando se crea programáticamente una cadena de texto, use Array#join en vez de concatenación. Sobretodo por IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). 215 | 216 | ```javascript 217 | var items; 218 | var messages; 219 | var length; 220 | var i; 221 | 222 | messages = [{ 223 | state: 'success', 224 | message: 'This one worked.' 225 | },{ 226 | state: 'success', 227 | message: 'This one worked as well.' 228 | },{ 229 | state: 'error', 230 | message: 'This one did not work.' 231 | }]; 232 | 233 | length = messages.length; 234 | 235 | // mal 236 | function inbox(messages) { 237 | items = ''; 244 | } 245 | 246 | // bien 247 | function inbox(messages) { 248 | items = []; 249 | 250 | for (i = 0; i < length; i++) { 251 | // usa asignacion directa aqui porque estamos micro-optimizando 252 | items[i] = '
  • ' + messages[i].message + '
  • '; 253 | } 254 | 255 | return ''; 256 | } 257 | ``` 258 | 259 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 260 | 261 | 262 | ## Funciones 263 | 264 | - Expresiones de función: 265 | 266 | ```javascript 267 | // expresion de funcion anonima 268 | var anonymous = function() { 269 | return true; 270 | }; 271 | 272 | // expresion de funcion nombrada 273 | var named = function named() { 274 | return true; 275 | }; 276 | 277 | // expresion de funcion inmediatamente invocada (IIFE) 278 | (function() { 279 | console.log('Welcome to the Internet. Please follow me.'); 280 | })(); 281 | ``` 282 | 283 | - Nunca declares una función en un bloque que no sea de función (if, while, etc). En vez de ello, asigna la función a una variable. Los navegadores te permitirán hacerlo pero todos ellos lo interpretarán de modo diferente, lo que es lamentable. 284 | 285 | > **Nota:** ECMA-262 define un bloque como una lista de sentencias. Una declaración de función no es una sentencia. [Lee la nota de ECMA-262 sobre este inconveniente](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). 286 | 287 | ```javascript 288 | // mal 289 | if (currentUser) { 290 | function test() { 291 | console.log('Nope.'); 292 | } 293 | } 294 | 295 | // bien 296 | var test; 297 | if (currentUser) { 298 | test = function test() { 299 | console.log('Yup.'); 300 | }; 301 | } 302 | ``` 303 | 304 | - Nunca nombres a un parámetro como `arguments`, esto tendrá precedencia sobre el objeto `arguments` que es brindado en cada ámbito de función. 305 | 306 | ```javascript 307 | // mal 308 | function nope(name, options, arguments) { 309 | // ...algo... 310 | } 311 | 312 | // bien 313 | function yup(name, options, args) { 314 | // ...algo... 315 | } 316 | ``` 317 | 318 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 319 | 320 | 321 | 322 | ## Propiedades 323 | 324 | - Usa la notación de punto `.` cuando accedas a las propiedades. 325 | 326 | ```javascript 327 | var luke = { 328 | jedi: true, 329 | age: 28 330 | }; 331 | 332 | // mal 333 | var isJedi = luke['jedi']; 334 | 335 | // bien 336 | var isJedi = luke.jedi; 337 | ``` 338 | 339 | - Usa la notación subscript `[]` cuando accedas a las propiedades con una variable. 340 | 341 | ```javascript 342 | var luke = { 343 | jedi: true, 344 | age: 28 345 | }; 346 | 347 | function getProp(prop) { 348 | return luke[prop]; 349 | } 350 | 351 | var isJedi = getProp('jedi'); 352 | ``` 353 | 354 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 355 | 356 | 357 | ## Variables 358 | 359 | - Siempre usa `var` para declarar variables. No hacerlo resultará en variables globales. Debemos evitar contaminar el espacio global (global namespace). El [Capitán Planeta](https://es.wikipedia.org/wiki/Capit%C3%A1n_Planeta_y_los_planetarios) nos advirtió de eso. 360 | 361 | ```javascript 362 | // mal 363 | superPower = new SuperPower(); 364 | 365 | // bien 366 | var superPower = new SuperPower(); 367 | ``` 368 | 369 | - Usa una declaración `var` por variable. Es más fácil agregar nuevas declaraciones de variables de este modo, y no tendrás que preocuparte por reemplazar `;` por `,` o introducir diffs de sólo puntuación . 370 | 371 | ```javascript 372 | // mal 373 | var items = getItems(), 374 | goSportsTeam = true, 375 | dragonball = 'z'; 376 | 377 | // mal 378 | // (compara con lo de arriba y encuentra el error) 379 | var items = getItems(), 380 | goSportsTeam = true; 381 | dragonball = 'z'; 382 | 383 | // bien 384 | var items = getItems(); 385 | var goSportsTeam = true; 386 | var dragonball = 'z'; 387 | ``` 388 | 389 | - Declara a las variables sin asignación al final. Esto es útil cuando necesites asignar una variable luego dependiendo de una de las variables asignadas previamente. 390 | 391 | ```javascript 392 | // mal 393 | var i, len, dragonball, 394 | items = getItems(), 395 | goSportsTeam = true; 396 | 397 | // mal 398 | var i; 399 | var items = getItems(); 400 | var dragonball; 401 | var goSportsTeam = true; 402 | var len; 403 | 404 | // bien 405 | var items = getItems(); 406 | var goSportsTeam = true; 407 | var dragonball; 408 | var length; 409 | var i; 410 | ``` 411 | 412 | - Asigna las variables al inicio de su ámbito. Esto ayuda a evitar inconvenientes con la declaración de variables y temas relacionados a 'hoisting'. 413 | 414 | ```javascript 415 | // mal 416 | function() { 417 | test(); 418 | console.log('doing stuff..'); 419 | 420 | //..otras cosas.. 421 | 422 | var name = getName(); 423 | 424 | if (name === 'test') { 425 | return false; 426 | } 427 | 428 | return name; 429 | } 430 | 431 | // bien 432 | function() { 433 | var name = getName(); 434 | 435 | test(); 436 | console.log('doing stuff..'); 437 | 438 | //..otras cosas.. 439 | 440 | if (name === 'test') { 441 | return false; 442 | } 443 | 444 | return name; 445 | } 446 | 447 | // mal - llamada a funcion innecesaria 448 | function() { 449 | var name = getName(); 450 | 451 | if (!arguments.length) { 452 | return false; 453 | } 454 | 455 | this.setFirstName(name); 456 | 457 | return true; 458 | } 459 | 460 | // bien 461 | function() { 462 | if (!arguments.length) { 463 | return false; 464 | } 465 | 466 | var name = getName(); 467 | this.setFirstName(name); 468 | 469 | return true; 470 | } 471 | ``` 472 | 473 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 474 | 475 | 476 | ## Hoisting 477 | 478 | - Las declaraciones de variables son movidas a la parte superior de su ámbito, sin embargo su asignación no. 479 | 480 | ```javascript 481 | // sabemos que esto no funcionara (asumiendo 482 | // que no hay una variable global notDefined) 483 | function example() { 484 | console.log(notDefined); // => lanza un ReferenceError 485 | } 486 | 487 | // crear una declaracion de variable luego 488 | // que referencies a la variable funcionara 489 | // por el hoisting. Nota: A la asignacion 490 | // del valor `true` no se le aplico hoisting. 491 | function example() { 492 | console.log(declaredButNotAssigned); // => undefined 493 | var declaredButNotAssigned = true; 494 | } 495 | 496 | // El interprete lleva la declaracion de la 497 | // variable a la parte superior de la funcion. 498 | // Eso significa que nuestro ejemplo 499 | // podria ser reescrito como: 500 | function example() { 501 | var declaredButNotAssigned; 502 | console.log(declaredButNotAssigned); // => undefined 503 | declaredButNotAssigned = true; 504 | } 505 | ``` 506 | 507 | - Expresiones de función anónimas hacen hoisting de su nombre de variable, pero no de la asignación de la función. 508 | 509 | ```javascript 510 | function example() { 511 | console.log(anonymous); // => undefined 512 | 513 | anonymous(); // => TypeError anonymous is not a function 514 | 515 | var anonymous = function() { 516 | console.log('anonymous function expression'); 517 | }; 518 | } 519 | ``` 520 | 521 | - Expresiones de función nombradas hacen hoisting de su nombre de variable, pero no del nombre de la función ni del contenido de la función. 522 | 523 | ```javascript 524 | function example() { 525 | console.log(named); // => undefined 526 | 527 | named(); // => TypeError named is not a function 528 | 529 | superPower(); // => ReferenceError superPower is not defined 530 | 531 | var named = function superPower() { 532 | console.log('Flying'); 533 | }; 534 | } 535 | 536 | // lo mismo es cierto cuando el nombre 537 | // de la funcion es igual al nombre de 538 | // la variable. 539 | function example() { 540 | console.log(named); // => undefined 541 | 542 | named(); // => TypeError named is not a function 543 | 544 | var named = function named() { 545 | console.log('named'); 546 | } 547 | } 548 | ``` 549 | 550 | - Las declaraciones de función hacen hoist de su nombre y del contenido de la función. 551 | 552 | ```javascript 553 | function example() { 554 | superPower(); // => Flying 555 | 556 | function superPower() { 557 | console.log('Flying'); 558 | } 559 | } 560 | ``` 561 | 562 | - Para más información lee [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) por [Ben Cherry](http://www.adequatelygood.com/) 563 | 564 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 565 | 566 | 567 | 568 | ## Expresiones de comparación e igualdad 569 | 570 | - Usa `===` y `!==` en vez de `==` y `!=` respectivamente. 571 | - Expresiones condicionales son evaluadas usando coerción con el método `ToBoolean` y siempre obedecen a estas reglas sencillas: 572 | 573 | + **Objects** son evaluados como **true** (también considera así al objeto vacío ```{}``` y arreglos sin contenido ```[]```) 574 | + **Undefined** es evaluado como **false** 575 | + **Null** es evaluado como **false** 576 | + **Booleans** son evaluados como **el valor del booleano** 577 | + **Numbers** son evaluados como **false** si **+0**, **-0**, o **NaN**, de otro modo **true** 578 | + **Strings** son evaluados como **false** si es una cadena de texto vacía `''`, de otro modo son **true** 579 | 580 | ```javascript 581 | if ([0]) { 582 | // true 583 | // un arreglo es un objeto, los objetos son evaluados como true 584 | } 585 | ``` 586 | 587 | - Usa atajos. 588 | 589 | ```javascript 590 | // mal 591 | if (name !== '') { 592 | // ...stuff... 593 | } 594 | 595 | // bien 596 | if (name) { 597 | // ...stuff... 598 | } 599 | 600 | // mal 601 | if (collection.length > 0) { 602 | // ...stuff... 603 | } 604 | 605 | // bien 606 | if (collection.length) { 607 | // ...stuff... 608 | } 609 | ``` 610 | 611 | - Para más información revisa [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) por Angus Croll 612 | 613 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 614 | 615 | 616 | ## Bloques 617 | 618 | - Usa llaves con todos los bloques de múltiples líneas. 619 | 620 | ```javascript 621 | // mal 622 | if (test) 623 | return false; 624 | 625 | // bien 626 | if (test) return false; 627 | 628 | // bien 629 | if (test) { 630 | return false; 631 | } 632 | 633 | // mal 634 | function() { return false; } 635 | 636 | // bien 637 | function() { 638 | return false; 639 | } 640 | ``` 641 | 642 | - Si estás usando bloques de muchas líneas con ```if``` y ```else```, pon el ```else``` en la misma línea que el ```if```. 643 | 644 | ```javascript 645 | // mal 646 | if (test) { 647 | thing1(); 648 | thing2(); 649 | } 650 | else { 651 | thing3(); 652 | } 653 | 654 | // bien 655 | if (test) { 656 | thing1(); 657 | thing2(); 658 | } else { 659 | thing3(); 660 | } 661 | ``` 662 | 663 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 664 | 665 | 666 | ## Comentarios 667 | 668 | - Usa `/** ... */` para comentarios de múltiples líneas. Incluye una descripción, especificación de tipos y valores para todos los parámetros y valores de retorno. 669 | 670 | ```javascript 671 | // mal 672 | // make() returns a new element 673 | // based on the passed in tag name 674 | // 675 | // @param {String} tag 676 | // @return {Element} element 677 | function make(tag) { 678 | 679 | // ...stuff... 680 | 681 | return element; 682 | } 683 | 684 | // bien 685 | /** 686 | * make() returns a new element 687 | * based on the passed in tag name 688 | * 689 | * @param {String} tag 690 | * @return {Element} element 691 | */ 692 | function make(tag) { 693 | 694 | // ...stuff... 695 | 696 | return element; 697 | } 698 | ``` 699 | 700 | - Usa `//` para comentarios de una sola línea. Ubica los comentarios de una sola línea encima de la sentencia comentada. Deja una línea en blanco antes del comentario. 701 | 702 | ```javascript 703 | // mal 704 | var active = true; // is current tab 705 | 706 | // bien 707 | // is current tab 708 | var active = true; 709 | 710 | // mal 711 | function getType() { 712 | console.log('fetching type...'); 713 | // set the default type to 'no type' 714 | var type = this._type || 'no type'; 715 | 716 | return type; 717 | } 718 | 719 | // bien 720 | function getType() { 721 | console.log('fetching type...'); 722 | 723 | // set the default type to 'no type' 724 | var type = this._type || 'no type'; 725 | 726 | return type; 727 | } 728 | ``` 729 | 730 | - Agregando a tus comentarios los prefijos `FIXME` o `TODO`, ayudará a otros desarrolladores a entender rápidamente si estás apuntando a un problema que precisa ser revisado o si estás sugiriendo una solución al problema que debería ser implementado. Estos son diferentes a comentarios regulares en el sentido que requieren alguna acción. Las acciones son `FIXME -- necesito resolver esto` o `TODO -- necesita implementarse`. 731 | 732 | - Usa `// FIXME:` para anotar problemas. 733 | 734 | ```javascript 735 | function Calculator() { 736 | 737 | // FIXME: shouldn't use a global here 738 | total = 0; 739 | 740 | return this; 741 | } 742 | ``` 743 | 744 | - Usa `// TODO:` para anotar soluciones a los problemas. 745 | 746 | ```javascript 747 | function Calculator() { 748 | 749 | // TODO: total should be configurable by an options param 750 | this.total = 0; 751 | 752 | return this; 753 | } 754 | ``` 755 | 756 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 757 | 758 | 759 | ## Espacios en blanco 760 | 761 | - Usa indentaciones blandas (sin TAB) establecidas en dos espacios. 762 | 763 | ```javascript 764 | // mal 765 | function() { 766 | ∙∙∙∙var name; 767 | } 768 | 769 | // mal 770 | function() { 771 | ∙var name; 772 | } 773 | 774 | // bien 775 | function() { 776 | ∙∙var name; 777 | } 778 | ``` 779 | - Deja un espacio antes de la llave de apertura. 780 | 781 | ```javascript 782 | // mal 783 | function test(){ 784 | console.log('test'); 785 | } 786 | 787 | // bien 788 | function test() { 789 | console.log('test'); 790 | } 791 | 792 | // mal 793 | dog.set('attr',{ 794 | age: '1 year', 795 | breed: 'Bernese Mountain Dog' 796 | }); 797 | 798 | // bien 799 | dog.set('attr', { 800 | age: '1 year', 801 | breed: 'Bernese Mountain Dog' 802 | }); 803 | ``` 804 | 805 | - Deja un espacio antes del paréntesis de apertura en las sentencias de control (```if```, ```while```, etc.). No dejes espacios antes de la lista de argumentos en las invocaciones y declaraciones de funciones. 806 | ```javascript 807 | // mal 808 | if(isJedi) { 809 | fight (); 810 | } 811 | 812 | // bien 813 | if (isJedi) { 814 | fight(); 815 | } 816 | 817 | // mal 818 | function fight () { 819 | console.log ('Swooosh!'); 820 | } 821 | 822 | // bien 823 | function fight() { 824 | console.log('Swooosh!'); 825 | } 826 | ``` 827 | 828 | - Separa a los operadores con espacios. 829 | ```javascript 830 | // mal 831 | var x=y+5; 832 | 833 | // bien 834 | var x = y + 5; 835 | ``` 836 | 837 | - Deja una línea en blanco al final del archivo. 838 | 839 | ```javascript 840 | // mal 841 | (function(global) { 842 | // ...algo... 843 | })(this); 844 | ``` 845 | 846 | ```javascript 847 | // mal 848 | (function(global) { 849 | // ...algo... 850 | })(this);↵ 851 | ↵ 852 | 853 | ``` 854 | 855 | ```javascript 856 | // bien 857 | (function(global) { 858 | // ...algo... 859 | })(this);↵ 860 | 861 | ``` 862 | 863 | - Usa indentación cuando uses métodos largos con 'chaining'. Emplea un punto adelante en cada nueva línea, lo que enfatiza que es un método llamado no una nueva sentencia. 864 | 865 | ```javascript 866 | // mal 867 | $('#items').find('.selected').highlight().end().find('.open').updateCount(); 868 | 869 | // mal 870 | $('#items'). 871 | find('.selected'). 872 | highlight(). 873 | end(). 874 | find('.open'). 875 | updateCount(); 876 | 877 | // bien 878 | $('#items') 879 | .find('.selected') 880 | .highlight() 881 | .end() 882 | .find('.open') 883 | .updateCount(); 884 | 885 | // mal 886 | var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) 887 | .attr('width', (radius + margin) * 2).append('svg:g') 888 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 889 | .call(tron.led); 890 | 891 | // bien 892 | var leds = stage.selectAll('.led') 893 | .data(data) 894 | .enter().append('svg:svg') 895 | .class('led', true) 896 | .attr('width', (radius + margin) * 2) 897 | .append('svg:g') 898 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 899 | .call(tron.led); 900 | ``` 901 | 902 | - Deja una línea en blanco luego de los bloques y antes de la siguiente sentencia. 903 | 904 | ```javascript 905 | // bad 906 | if (foo) { 907 | return bar; 908 | } 909 | return baz; 910 | 911 | // good 912 | if (foo) { 913 | return bar; 914 | } 915 | 916 | return baz; 917 | 918 | // bad 919 | var obj = { 920 | foo: function() { 921 | }, 922 | bar: function() { 923 | } 924 | }; 925 | return obj; 926 | 927 | // good 928 | var obj = { 929 | foo: function() { 930 | }, 931 | 932 | bar: function() { 933 | } 934 | }; 935 | 936 | return obj; 937 | ``` 938 | 939 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 940 | 941 | ## Comas 942 | 943 | - Comas al inicio de línea: **Nop.** 944 | 945 | ```javascript 946 | // mal 947 | var story = [ 948 | once 949 | , upon 950 | , aTime 951 | ]; 952 | 953 | // bien 954 | var story = [ 955 | once, 956 | upon, 957 | aTime 958 | ]; 959 | 960 | // mal 961 | var hero = { 962 | firstName: 'Bob' 963 | , lastName: 'Parr' 964 | , heroName: 'Mr. Incredible' 965 | , superPower: 'strength' 966 | }; 967 | 968 | // bien 969 | var hero = { 970 | firstName: 'Bob', 971 | lastName: 'Parr', 972 | heroName: 'Mr. Incredible', 973 | superPower: 'strength' 974 | }; 975 | ``` 976 | 977 | - Coma adicional al final: **Nop.** Esto puede provocar problemas en IE6/7 o IE9 si está en quirksmode. Además, en algunas implementaciones de ES3 se puede aumentar la longitud del arreglo si se tiene una coma adicional al final. Esto fue clarificado en ES5 ([fuente](http://es5.github.io/#D)): 978 | 979 | > La Edición 5 aclara el hecho de que dejar una coma al final de un ArrayInitialiser (inicialización de un arreglo) no aumenta la longitud del arreglo. Esto no es un cambio semántico a la Edición 3 pero algunas implementaciones tal vez malinterpretaron esto. 980 | 981 | ```javascript 982 | // mal 983 | var hero = { 984 | firstName: 'Kevin', 985 | lastName: 'Flynn', 986 | }; 987 | 988 | var heroes = [ 989 | 'Batman', 990 | 'Superman', 991 | ]; 992 | 993 | // bien 994 | var hero = { 995 | firstName: 'Kevin', 996 | lastName: 'Flynn' 997 | }; 998 | 999 | var heroes = [ 1000 | 'Batman', 1001 | 'Superman' 1002 | ]; 1003 | ``` 1004 | 1005 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1006 | 1007 | 1008 | ## Puntos y Comas 1009 | 1010 | - **Sip.** 1011 | 1012 | ```javascript 1013 | // mal 1014 | (function() { 1015 | var name = 'Skywalker' 1016 | return name 1017 | })() 1018 | 1019 | // bien 1020 | (function() { 1021 | var name = 'Skywalker'; 1022 | return name; 1023 | })(); 1024 | 1025 | // super bien (evita que la funcion se vuelva un argumento 1026 | // cuando dos archivos con IIFEs sean concatenados) 1027 | ;(function() { 1028 | var name = 'Skywalker'; 1029 | return name; 1030 | })(); 1031 | ``` 1032 | 1033 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1034 | 1035 | 1036 | ## Casting de Tipos & Coerción 1037 | 1038 | - Ejecuta coerción al inicio de una sentencia. 1039 | - Strings: 1040 | 1041 | ```javascript 1042 | // => this.reviewScore = 9; 1043 | 1044 | // mal 1045 | var totalScore = this.reviewScore + ''; 1046 | 1047 | // bien 1048 | var totalScore = '' + this.reviewScore; 1049 | 1050 | // mal 1051 | var totalScore = '' + this.reviewScore + ' total score'; 1052 | 1053 | // bien 1054 | var totalScore = this.reviewScore + ' total score'; 1055 | ``` 1056 | 1057 | - Usa `parseInt` para números y siempre con la base numérica para el casting de tipo. 1058 | 1059 | ```javascript 1060 | var inputValue = '4'; 1061 | 1062 | // mal 1063 | var val = new Number(inputValue); 1064 | 1065 | // mal 1066 | var val = +inputValue; 1067 | 1068 | // mal 1069 | var val = inputValue >> 0; 1070 | 1071 | // mal 1072 | var val = parseInt(inputValue); 1073 | 1074 | // bien 1075 | var val = Number(inputValue); 1076 | 1077 | // bien 1078 | var val = parseInt(inputValue, 10); 1079 | ``` 1080 | 1081 | - Si por alguna razón estás haciendo algo salvaje y `parseInt` es un cuello de botella por lo que necesitaste usar Bitshift por [razones de desempeño](http://jsperf.com/coercion-vs-casting/3), deja un comentario explicando qué y porqué lo estás haciendo. 1082 | 1083 | ```javascript 1084 | // bien 1085 | /** 1086 | * parseInt was the reason my code was slow. 1087 | * Bitshifting the String to coerce it to a 1088 | * Number made it a lot faster. 1089 | */ 1090 | var val = inputValue >> 0; 1091 | ``` 1092 | 1093 | > **Nota:** Ten mucho cuidado al hacer operaciones de Bitshift. En Javascript los números son representados como [valores de 64-bit](http://es5.github.io/#x4.3.19), sin embargo las operaciones de Bitshift siempre retornan un entero de 32-bits ([fuente](http://es5.github.io/#x11.7)). Bitshift puede presentarnos un comportamiento inesperado para valores enteros mayores a 32 bits. [Discusión](https://github.com/airbnb/javascript/issues/109). El mayor entero con signo de 32 bits es 2,147,483,647: 1094 | ```javascript 1095 | 2147483647 >> 0 //=> 2147483647 1096 | 2147483648 >> 0 //=> -2147483648 1097 | 2147483649 >> 0 //=> -2147483647 1098 | ``` 1099 | 1100 | - Booleans: 1101 | 1102 | ```javascript 1103 | var age = 0; 1104 | 1105 | // mal 1106 | var hasAge = new Boolean(age); 1107 | 1108 | // bien 1109 | var hasAge = Boolean(age); 1110 | 1111 | // bien 1112 | var hasAge = !!age; 1113 | ``` 1114 | 1115 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1116 | 1117 | 1118 | ## Convenciones de nomenclatura 1119 | 1120 | - Evita nombres de una sola letra. Sé descriptivo con tus nombres. 1121 | 1122 | ```javascript 1123 | // mal 1124 | function q() { 1125 | // ...algo... 1126 | } 1127 | 1128 | // bien 1129 | function query() { 1130 | // ...algo... 1131 | } 1132 | ``` 1133 | 1134 | - Usa camelCase cuando nombres tus objetos, funciones e instancias. 1135 | 1136 | ```javascript 1137 | // mal 1138 | var OBJEcttsssss = {}; 1139 | var this_is_my_object = {}; 1140 | var o = {}; 1141 | function c() {} 1142 | 1143 | // bien 1144 | var thisIsMyObject = {}; 1145 | function thisIsMyFunction() {} 1146 | ``` 1147 | 1148 | - Usa PascalCase cuando nombres constructores o clases. 1149 | 1150 | ```javascript 1151 | // mal 1152 | function user(options) { 1153 | this.name = options.name; 1154 | } 1155 | 1156 | var bad = new user({ 1157 | name: 'nope' 1158 | }); 1159 | 1160 | // bien 1161 | function User(options) { 1162 | this.name = options.name; 1163 | } 1164 | 1165 | var good = new User({ 1166 | name: 'yup' 1167 | }); 1168 | ``` 1169 | 1170 | - Usa un guión bajo `_` adelante de la variable cuando nombres propiedades privadas. 1171 | 1172 | ```javascript 1173 | // mal 1174 | this.__firstName__ = 'Panda'; 1175 | this.firstName_ = 'Panda'; 1176 | 1177 | // bien 1178 | this._firstName = 'Panda'; 1179 | ``` 1180 | 1181 | - Cuando guardes una referencia a `this` usa `_this`. 1182 | 1183 | ```javascript 1184 | // mal 1185 | function() { 1186 | var self = this; 1187 | return function() { 1188 | console.log(self); 1189 | }; 1190 | } 1191 | 1192 | // mal 1193 | function() { 1194 | var that = this; 1195 | return function() { 1196 | console.log(that); 1197 | }; 1198 | } 1199 | 1200 | // bien 1201 | function() { 1202 | var _this = this; 1203 | return function() { 1204 | console.log(_this); 1205 | }; 1206 | } 1207 | ``` 1208 | 1209 | - Nombra tus funciones. Esto será de ayuda cuando hagas seguimiento de la pila de llamadas (e.g. en caso de errores). 1210 | 1211 | ```javascript 1212 | // mal 1213 | var log = function(msg) { 1214 | console.log(msg); 1215 | }; 1216 | 1217 | // bien 1218 | var log = function log(msg) { 1219 | console.log(msg); 1220 | }; 1221 | ``` 1222 | 1223 | > **Nota:** En IE8 e inferiores se tienen algunas inconveniencias con las expresiones de función nombradas. Mira http://kangax.github.io/nfe/ para más información. 1224 | 1225 | - Si tu archivo exporta una sola clase, el nombre de tu archivo debe ser exactamente el nombre de tu clase. 1226 | 1227 | ```javascript 1228 | // contenido del archivo 1229 | class CheckBox { 1230 | // ... 1231 | } 1232 | module.exports = CheckBox; 1233 | 1234 | // en algun otro archivo 1235 | // mal 1236 | var CheckBox = require('./checkBox'); 1237 | 1238 | // mal 1239 | var CheckBox = require('./check_box'); 1240 | 1241 | // bien 1242 | var CheckBox = require('./CheckBox'); 1243 | ``` 1244 | 1245 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1246 | 1247 | 1248 | ## Funciones de Acceso 1249 | 1250 | - Funciones de acceso para las propiedades no son requeridas. 1251 | - Si creas funciones de acceso usa ```getVal()``` y ```setVal('hello')```. 1252 | 1253 | ```javascript 1254 | // mal 1255 | dragon.age(); 1256 | 1257 | // bien 1258 | dragon.getAge(); 1259 | 1260 | // mal 1261 | dragon.age(25); 1262 | 1263 | // bien 1264 | dragon.setAge(25); 1265 | ``` 1266 | 1267 | - Si la propiedad es un booleano, usa ```isVal()``` o ```hasVal()```. 1268 | 1269 | ```javascript 1270 | // mal 1271 | if (!dragon.age()) { 1272 | return false; 1273 | } 1274 | 1275 | // bien 1276 | if (!dragon.hasAge()) { 1277 | return false; 1278 | } 1279 | ``` 1280 | 1281 | - Está bien crear funciones ```get()``` y ```set()```, pero sé consistente. 1282 | 1283 | ```javascript 1284 | function Jedi(options) { 1285 | options || (options = {}); 1286 | var lightsaber = options.lightsaber || 'blue'; 1287 | this.set('lightsaber', lightsaber); 1288 | } 1289 | 1290 | Jedi.prototype.set = function(key, val) { 1291 | this[key] = val; 1292 | }; 1293 | 1294 | Jedi.prototype.get = function(key) { 1295 | return this[key]; 1296 | }; 1297 | ``` 1298 | 1299 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1300 | 1301 | 1302 | ## Constructores 1303 | 1304 | - Asigna métodos al objeto prototype, en vez de sobreescribir prototype con un nuevo objeto. La sobreescritura de prototype hace la herencia imposible: ¡reseteando prototype sobreescribirás la base! 1305 | 1306 | ```javascript 1307 | function Jedi() { 1308 | console.log('new jedi'); 1309 | } 1310 | 1311 | // mal 1312 | Jedi.prototype = { 1313 | fight: function fight() { 1314 | console.log('fighting'); 1315 | }, 1316 | 1317 | block: function block() { 1318 | console.log('blocking'); 1319 | } 1320 | }; 1321 | 1322 | // bien 1323 | Jedi.prototype.fight = function fight() { 1324 | console.log('fighting'); 1325 | }; 1326 | 1327 | Jedi.prototype.block = function block() { 1328 | console.log('blocking'); 1329 | }; 1330 | ``` 1331 | 1332 | - Métodos pueden retornar `this` para ayudar con el encadenamiento de métodos (chaining). 1333 | 1334 | ```javascript 1335 | // mal 1336 | Jedi.prototype.jump = function() { 1337 | this.jumping = true; 1338 | return true; 1339 | }; 1340 | 1341 | Jedi.prototype.setHeight = function(height) { 1342 | this.height = height; 1343 | }; 1344 | 1345 | var luke = new Jedi(); 1346 | luke.jump(); // => true 1347 | luke.setHeight(20) // => undefined 1348 | 1349 | // bien 1350 | Jedi.prototype.jump = function() { 1351 | this.jumping = true; 1352 | return this; 1353 | }; 1354 | 1355 | Jedi.prototype.setHeight = function(height) { 1356 | this.height = height; 1357 | return this; 1358 | }; 1359 | 1360 | var luke = new Jedi(); 1361 | 1362 | luke.jump() 1363 | .setHeight(20); 1364 | ``` 1365 | 1366 | 1367 | - Está bien escribir un método toString() personalizado, solo asegúrate que funcione correctamente y no cause efectos colaterales. 1368 | 1369 | ```javascript 1370 | function Jedi(options) { 1371 | options || (options = {}); 1372 | this.name = options.name || 'no name'; 1373 | } 1374 | 1375 | Jedi.prototype.getName = function getName() { 1376 | return this.name; 1377 | }; 1378 | 1379 | Jedi.prototype.toString = function toString() { 1380 | return 'Jedi - ' + this.getName(); 1381 | }; 1382 | ``` 1383 | 1384 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1385 | 1386 | 1387 | ## Eventos 1388 | 1389 | - Cuando envíes paquetes de datos a los eventos (ya sea con eventos del DOM o algo propietario como los eventos de Backbone), pasa un mapa en vez de un valor directo. Esto permitirá a un próximo colaborador a agregar más datos al paquete de datos sin que tenga que encontrar o actualizar un handler para cada evento. Por ejemplo, en vez de: 1390 | 1391 | ```js 1392 | // mal 1393 | $(this).trigger('listingUpdated', listing.id); 1394 | 1395 | ... 1396 | 1397 | $(this).on('listingUpdated', function(e, listingId) { 1398 | // hacer algo con listingId 1399 | }); 1400 | ``` 1401 | 1402 | prefiere: 1403 | 1404 | ```js 1405 | // bien 1406 | $(this).trigger('listingUpdated', { listingId : listing.id }); 1407 | 1408 | ... 1409 | 1410 | $(this).on('listingUpdated', function(e, data) { 1411 | // hacer algo con data.listingId 1412 | }); 1413 | ``` 1414 | 1415 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1416 | 1417 | 1418 | ## Módulos 1419 | 1420 | - El módulo debe empezar con un `!`. Esto asegura que si un módulo mal formado olvide incluir al final un punto y coma, no hayan errores en producción cuando los scripts sean concatenados. [Explicación](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) 1421 | - El archivo debe ser nombrado con camelCase, residir en un fólder con el mismo nombre, y corresponder al nombre de la función a exportar. 1422 | - Agrega un método `noConflict()` que reestablezca el módulo exportado a la versión anterior y retorne este módulo (para ser asignado a una variable). 1423 | - Siempre declara `'use strict';` al inicio de cada módulo. 1424 | 1425 | ```javascript 1426 | // fancyInput/fancyInput.js 1427 | 1428 | !function(global) { 1429 | 'use strict'; 1430 | 1431 | var previousFancyInput = global.FancyInput; 1432 | 1433 | function FancyInput(options) { 1434 | this.options = options || {}; 1435 | } 1436 | 1437 | FancyInput.noConflict = function noConflict() { 1438 | global.FancyInput = previousFancyInput; 1439 | return FancyInput; 1440 | }; 1441 | 1442 | global.FancyInput = FancyInput; 1443 | }(this); 1444 | ``` 1445 | 1446 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1447 | 1448 | 1449 | ## jQuery 1450 | 1451 | - Nombre las variables de objetos jQuery con un prefijo `$`. 1452 | 1453 | ```javascript 1454 | // mal 1455 | var sidebar = $('.sidebar'); 1456 | 1457 | // bien 1458 | var $sidebar = $('.sidebar'); 1459 | ``` 1460 | 1461 | - Guarde en variables los lookups de jQuery que se necesiten posteriormente. 1462 | 1463 | ```javascript 1464 | // mal 1465 | function setSidebar() { 1466 | $('.sidebar').hide(); 1467 | 1468 | // ...algo... 1469 | 1470 | $('.sidebar').css({ 1471 | 'background-color': 'pink' 1472 | }); 1473 | } 1474 | 1475 | // bien 1476 | function setSidebar() { 1477 | var $sidebar = $('.sidebar'); 1478 | $sidebar.hide(); 1479 | 1480 | // ...algo... 1481 | 1482 | $sidebar.css({ 1483 | 'background-color': 'pink' 1484 | }); 1485 | } 1486 | ``` 1487 | 1488 | - Para consultas de elementos DOM usa el modo Cascada `$('.sidebar ul')` o parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) 1489 | - Usa `find` solo con consultas guardadas en variables previamente. 1490 | 1491 | ```javascript 1492 | // mal 1493 | $('ul', '.sidebar').hide(); 1494 | 1495 | // mal 1496 | $('.sidebar').find('ul').hide(); 1497 | 1498 | // bien 1499 | $('.sidebar ul').hide(); 1500 | 1501 | // bien 1502 | $('.sidebar > ul').hide(); 1503 | 1504 | // bien 1505 | $sidebar.find('ul'); 1506 | ``` 1507 | 1508 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1509 | 1510 | 1511 | ## Compatibilidad con ECMAScript 5 1512 | 1513 | - Revisa la [tabla de compatibilidad](http://kangax.github.com/es5-compat-table/) de ES5 de [Kangax](https://twitter.com/kangax/). 1514 | 1515 | **[[⬆]](#TOC)** 1516 | 1517 | 1518 | ## Pruebas 1519 | 1520 | - **Sip**. 1521 | 1522 | ```javascript 1523 | function() { 1524 | return true; 1525 | } 1526 | ``` 1527 | 1528 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1529 | 1530 | 1531 | ## Desempeño 1532 | 1533 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) 1534 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) 1535 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) 1536 | - [Bang Function](http://jsperf.com/bang-function) 1537 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) 1538 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) 1539 | - [Long String Concatenation](http://jsperf.com/ya-string-concat) 1540 | - Loading... 1541 | 1542 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1543 | 1544 | 1545 | ## Recursos 1546 | 1547 | 1548 | **Lee esto** 1549 | 1550 | - [Annotated ECMAScript 5.1](http://es5.github.com/) 1551 | 1552 | **Tools** 1553 | 1554 | Code Style Linters 1555 | - [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) 1556 | - [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) 1557 | 1558 | **Otras guías de estilo** 1559 | 1560 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) (Guía de Estilo de Javascript de Google) 1561 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) (Lineamientos de Estilo con el núcleo de jQuery) 1562 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) (Idiomatic Javascript: Principios de Escritura Consistente) 1563 | - [JavaScript Standard Style](https://github.com/feross/standard) (Estilo estándar de JavaScript) 1564 | 1565 | **Otros estilos** 1566 | 1567 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen (Nomenclatura en funciones anidadas) 1568 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) (Callbacks condicionales) 1569 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) (Convenciones Populares de Programación con Javascript en Github) 1570 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman (Múltiples sentencias var en JavaScript, no superfluas) 1571 | 1572 | **Lecturas más profundas** 1573 | 1574 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll (Entendiendo los Closures de JavaScript) 1575 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer (JavaScript Básico para el programador impaciente) 1576 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz (Podrías no necesitar jQuery) 1577 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban (Características de ES6) 1578 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock (Lineamientos para el Frontend) 1579 | 1580 | **Libros** 1581 | 1582 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford (JavaScript: Las Buenas Partes) 1583 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov (Patrones JavaScript) 1584 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz (Patrones de Diseño Avanzados en Javascript) 1585 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders (Sitios Web de Alto Desempeño: Conocimiento Esencial para los Ingenieros de Capa de Presentación) 1586 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas (JavaScript Mantenible) 1587 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw (Aplicaciones Web JavaScript) 1588 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig (Técnicas Avanzadas JavaScript) 1589 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch (Increíble Node.js: JavaScript en todas partes) 1590 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault (Secretos del JavaScript Ninja) 1591 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg (JavaScript Humano) 1592 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy (Superhéroe.js) 1593 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 1594 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov (JavaScript de Terceros) 1595 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman (JavaScript Efectivo: 68 modos específicos para elevar el poder de JavaScript) 1596 | - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke (JavaScript Elocuente) 1597 | - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson (No sabes JS) 1598 | 1599 | **Blogs** 1600 | 1601 | - [DailyJS](http://dailyjs.com/) 1602 | - [JavaScript Weekly](http://javascriptweekly.com/) 1603 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) 1604 | - [Bocoup Weblog](http://weblog.bocoup.com/) 1605 | - [Adequately Good](http://www.adequatelygood.com/) 1606 | - [NCZOnline](http://www.nczonline.net/) 1607 | - [Perfection Kills](http://perfectionkills.com/) 1608 | - [Ben Alman](http://benalman.com/) 1609 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 1610 | - [Dustin Diaz](http://dustindiaz.com/) 1611 | - [nettuts](http://net.tutsplus.com/?s=javascript) 1612 | 1613 | **Podcasts** 1614 | 1615 | - [JavaScript Jabber](http://devchat.tv/js-jabber/) 1616 | 1617 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1618 | 1619 | ## En la cancha 1620 | 1621 | Esta es una lista de las organizaciones que están usando esta guía de estilo. Envíanos un pull request o abre un issue y te agregaremos a la lista. 1622 | 1623 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 1624 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 1625 | - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript) 1626 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 1627 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 1628 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 1629 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 1630 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) 1631 | - **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 1632 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 1633 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 1634 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) 1635 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 1636 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 1637 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) 1638 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) 1639 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) 1640 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) 1641 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) 1642 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) 1643 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 1644 | - **Userify**: [userify/javascript](https://github.com/userify/javascript) 1645 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 1646 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 1647 | 1648 | ## Traducciones 1649 | 1650 | Esta guía de estilo es también disponible en otros lenguajes: 1651 | 1652 | - ![us](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/United-States.png) **Inglés (original)**: [airbnb/javascript](https://github.com/airbnb/javascript) 1653 | - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Portugués Brasileño**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) 1654 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Búlgaro**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 1655 | - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalán**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) 1656 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chino (Tradicional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 1657 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chino (Simplificado)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) 1658 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **Francés**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) 1659 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **Alemán**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) 1660 | - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italiano**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) 1661 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japonés**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) 1662 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Coreano**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) 1663 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polaco**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 1664 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Ruso**: [uprock/javascript](https://github.com/uprock/javascript) 1665 | - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Tailandés**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) 1666 | 1667 | ## La guía de la Guía de Estilos de Javascript 1668 | 1669 | - [Referencia](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 1670 | 1671 | ## Charla con nosotros sobre Javascript 1672 | - Encuéntranos en [gitter](https://gitter.im/airbnb/javascript). 1673 | 1674 | ## Colaboradores 1675 | 1676 | - [Vea a los colaboradores](https://github.com/airbnb/javascript/graphs/contributors) 1677 | 1678 | 1679 | ## Licencia 1680 | 1681 | (The MIT License) 1682 | 1683 | Copyright (c) 2012 Airbnb 1684 | 1685 | Permission is hereby granted, free of charge, to any person obtaining 1686 | a copy of this software and associated documentation files (the 1687 | 'Software'), to deal in the Software without restriction, including 1688 | without limitation the rights to use, copy, modify, merge, publish, 1689 | distribute, sublicense, and/or sell copies of the Software, and to 1690 | permit persons to whom the Software is furnished to do so, subject to 1691 | the following conditions: 1692 | 1693 | The above copyright notice and this permission notice shall be 1694 | included in all copies or substantial portions of the Software. 1695 | 1696 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 1697 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1698 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1699 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1700 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1701 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1702 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1703 | 1704 | **[[⬆ regresar a la Tabla de Contenido]](#TOC)** 1705 | 1706 | # }; 1707 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Airbnb JavaScript Style Guide() { 2 | 3 | *Un enfoque altamente razonable para JavaScript* 4 | 5 | > **Nota**: Esta guía asume que usas [Babel](https://babeljs.io), adicionalmente de tener instalado [babel-preset-airbnb](https://npmjs.com/babel-preset-airbnb) o su equivalente. También asume que tienes instalado shims/pollyfills en tu aplicación, con 6 | [airbnb-browser-shims](https://npmjs.com/airbnb-browser-shims) o su equivalente. 7 | 8 | [![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) 9 | [![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base) 10 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 11 | 12 | Otras Guías de Estilos 13 | - [ES5](es5/) (Obsoleto) 14 | - [React](https://github.com/agrcrobles/javascript/tree/master/react) 15 | - [CSS-in-JavaScript](https://github.com/airbnb/javascript/tree/master/css-in-javascript/) 16 | - [CSS & SASS](https://github.com/ismamz/css) 17 | - [Ruby](https://github.com/airbnb/ruby) 18 | 19 | ## Tabla de Contenido 20 | 21 | 1. [Tipos](#tipos) 22 | 1. [Referencias](#referencias) 23 | 1. [Objetos](#objetos) 24 | 1. [Arreglos](#arreglos) 25 | 1. [Destructuring](#destructuring) 26 | 1. [Cadenas de Texto](#cadenas-de-texto) 27 | 1. [Funciones](#funciones) 28 | 1. [Notación de Funciones de Flecha](#notación-de-funciones-de-flecha) 29 | 1. [Clases y Constructores](#clases-y-constructores) 30 | 1. [Módulos](#módulos) 31 | 1. [Iteradores y Generadores](#iteradores-y-generadores) 32 | 1. [Propiedades](#propiedades) 33 | 1. [Variables](#variables) 34 | 1. [Hoisting](#hoisting) 35 | 1. [Expresiones de comparación e igualdad](#expresiones-de-comparación-e-igualdad) 36 | 1. [Bloques](#bloques) 37 | 1. [Comentarios](#comentarios) 38 | 1. [Espacios en blanco](#espacios-en-blanco) 39 | 1. [Comas](#comas) 40 | 1. [Puntos y Comas](#puntos-y-comas) 41 | 1. [Casting de Tipos y Coerción](#casting-de-tipos-y-coerción) 42 | 1. [Convenciones de nomenclatura](#convenciones-de-nomenclatura) 43 | 1. [Funciones de Acceso](#funciones-de-acceso) 44 | 1. [Eventos](#eventos) 45 | 1. [jQuery](#jquery) 46 | 1. [Compatibilidad con EcmaScript 5](#compatibilidad-con-ecmascript-5) 47 | 1. [Estilos de EcmaScript6+ (ES2015+)](#estilos-de-ecmascript6-es-2015) 48 | 1. [Pruebas](#pruebas) 49 | 1. [Desempeño](#desempeño) 50 | 1. [Recursos](#recursos) 51 | 1. [En la cancha](#en-la-cancha) 52 | 1. [Traducciones](#traducciones) 53 | 1. [La guía de la Guía de Estilos JavaScript](#la-guía-de-la-guía-de-estilos-de-javascript) 54 | 1. [Charla con nosotros sobre Javascript](#charla-con-nosotros-sobre-javascript) 55 | 1. [Colaboradores](#colaboradores) 56 | 1. [Licencia](#licencia) 57 | 58 | ## Tipos 59 | 60 | - **Primitivos**: Cuando accedes a un tipo primitivo, manejas directamente su valor 61 | 62 | + `string` 63 | + `number` 64 | + `boolean` 65 | + `null` 66 | + `undefined` 67 | 68 | ```javascript 69 | const foo = 1; 70 | let bar = foo; 71 | 72 | bar = 9; 73 | 74 | console.log(foo, bar); // => 1, 9 75 | ``` 76 | - **Complejo**: Cuando accedes a un tipo complejo, manejas la referencia a su valor. 77 | 78 | + `object` 79 | + `array` 80 | + `function` 81 | 82 | ```javascript 83 | const foo = [1, 2]; 84 | const bar = foo; 85 | 86 | bar[0] = 9; 87 | 88 | console.log(foo[0], bar[0]); // => 9, 9 89 | ``` 90 | 91 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 92 | 93 | ## Referencias 94 | - Usa `const` para todas tus referencias; evita usar `var`. 95 | > ¿Por qué? Esto asegura que no reasignes tus referencias, lo 96 | que puede llevar a bugs y dificultad para comprender el código. 97 | 98 | ```javascript 99 | // mal 100 | var a = 1; 101 | var b = 2; 102 | 103 | // bien 104 | const a = 1; 105 | const b = 2; 106 | ``` 107 | 108 | - Si vas a reasignar referencias, usa `let` en vez de `var`. 109 | > ¿Por qué? El bloque `let` es de alcance a nivel de bloque a 110 | diferencia del alcance a nivel de función de `var`. 111 | 112 | ```javascript 113 | // mal 114 | var count = 1; 115 | if (true) { 116 | count += 1; 117 | } 118 | 119 | // bien, usa el let 120 | let count = 1; 121 | if (true) { 122 | count += 1; 123 | } 124 | ``` 125 | 126 | - Nota que tanto `let` como `const` tienen alcance a nivel de bloque. 127 | 128 | ```javascript 129 | // const y let solo existen en los bloques donde 130 | // estan definidos 131 | { 132 | let a = 1; 133 | const b = 1; 134 | } 135 | console.log(a); // ReferenceError 136 | console.log(b); // ReferenceError 137 | ``` 138 | 139 | ## Objetos 140 | 141 | - Usa la sintaxis literal para la creación de un objeto. 142 | 143 | ```javascript 144 | // mal 145 | const item = new Object(); 146 | 147 | // bien 148 | const item = {}; 149 | ``` 150 | 151 | - No uses [palabras reservadas](http://es5.github.io/#x7.6.1) para nombres de propiedades. No funciona en IE8 [Más información](https://github.com/airbnb/javascript/issues/61). No hay problema de usarlo en módulos de ES6 y en código de servidor. 152 | 153 | ```javascript 154 | // mal 155 | const superman = { 156 | default: { clark: 'kent' }, 157 | private: true 158 | }; 159 | 160 | // bien 161 | const superman = { 162 | defaults: { clark: 'kent' }, 163 | hidden: true 164 | }; 165 | ``` 166 | 167 | - Usa sinónimos legibles en lugar de palabras reservadas. 168 | 169 | ```javascript 170 | // mal 171 | const superman = { 172 | class: 'alien' 173 | }; 174 | 175 | // mal 176 | const superman = { 177 | klass: 'alien' 178 | }; 179 | 180 | // bien 181 | const superman = { 182 | type: 'alien' 183 | }; 184 | ``` 185 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 186 | 187 | ## Arreglos 188 | 189 | - Usa la sintaxis literal para la creación de arreglos 190 | 191 | ```javascript 192 | // mal 193 | const items = new Array(); 194 | 195 | // bien 196 | const items = []; 197 | ``` 198 | 199 | - Usa Array#push, en vez de asignación directa, para agregar elementos a un arreglo. 200 | 201 | ```javascript 202 | const someStack = []; 203 | 204 | // mal 205 | someStack[someStack.length] = 'abracadabra'; 206 | 207 | // bien 208 | someStack.push('abracadabra'); 209 | ``` 210 | 211 | - Usa [spread de arrays](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Operadores/Spread_operator) para copiar arreglos. 212 | 213 | ```javascript 214 | const len = items.length; 215 | const itemsCopy = []; 216 | let i; 217 | 218 | // mal 219 | for (i = 0; i < len; i++) { 220 | itemsCopy[i] = items[i]; 221 | } 222 | 223 | // bien 224 | const itemsCopy = [...items]; 225 | ``` 226 | 227 | - Para convertir un objeto ["array-like" (similar a un arreglo)](https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-7/array-like-objects) a un arreglo, usa Array#from. 228 | 229 | ```javascript 230 | const foo = document.querySelectorAll('.foo'); 231 | const nodes = Array.from(foo); 232 | ``` 233 | 234 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 235 | 236 | ## Destructuring 237 | 238 | - Usa object destructuring cuando accedas y uses múltiples propiedades de un objeto. 239 | 240 | > ¿Por qué? Destructuring te ahorra crear referencias temporales para esas propiedades. 241 | 242 | ```javascript 243 | // mal 244 | function getFullName(user) { 245 | const firstName = user.firstName; 246 | const lastName = user.lastName; 247 | 248 | return `${firstName} ${lastName}`; 249 | } 250 | 251 | // bien 252 | function getFullName(user) { 253 | const { firstName, lastName } = user; 254 | return `${firstName} ${lastName}`; 255 | } 256 | 257 | // mejor 258 | function getFullName({ firstName, lastName }) { 259 | return `${firstName} ${lastName}`; 260 | } 261 | ``` 262 | 263 | - Usa array destructuring. 264 | 265 | ```javascript 266 | const arr = [1, 2, 3, 4]; 267 | 268 | // mal 269 | const first = arr[0]; 270 | const second = arr[1]; 271 | 272 | // bien 273 | const [first, second] = arr; 274 | ``` 275 | 276 | - Usa object destructuring para múltiple valores de retorno, no array destructuring. 277 | 278 | > ¿Por qué? Puedes agregar nuevas propiedades en el tiempo o cambiar el orden de las cosas sin afectar la forma en que se llama. 279 | 280 | ```javascript 281 | // mal 282 | function processInput(input) { 283 | // then a miracle occurs 284 | return [left, right, top, bottom]; 285 | } 286 | 287 | // el que llama necesita pensar en el orden de la data de retorno 288 | const [left, __, top] = processInput(input); 289 | 290 | // bien 291 | function processInput(input) { 292 | // then a miracle occurs 293 | return { left, right, top, bottom }; 294 | } 295 | 296 | // el que llama elige solo la data que necesita 297 | const { left, top } = processInput(input); 298 | ``` 299 | 300 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 301 | 302 | 303 | ## Cadenas de Texto 304 | 305 | - Usa comillas simples `''` para las cadenas de texto 306 | 307 | ```javascript 308 | // mal 309 | const name = "Bob Parr"; 310 | 311 | // bien 312 | const name = 'Bob Parr'; 313 | ``` 314 | 315 | - Las cadenas de texto con una longitud mayor a 100 caracteres deben ser escritas en múltiples líneas usando concatenación. 316 | 317 | > **Nota:** Cuando se usa sin criterio, las cadenas de texto largas pueden impactar en el desempeño. [jsPerf](http://jsperf.com/ya-string-concat) & [Discusión](https://github.com/airbnb/javascript/issues/40) 318 | 319 | ```javascript 320 | // mal 321 | var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; 322 | 323 | // bien 324 | var errorMessage = 'This is a super long error that was thrown because\ 325 | of Batman. When you stop to think about how Batman had anything to do \ 326 | with this, you would get nowhere fast.'; 327 | 328 | // bien 329 | var errorMessage = 'This is a super long error that was thrown because' + 330 | 'of Batman. When you stop to think about how Batman had anything to do ' + 331 | 'with this, you would get nowhere fast.'; 332 | ``` 333 | 334 | - Cuando se crean cadenas de texto de forma programática, usa template strings (cadena de plantillas) en vez de concatenación. 335 | 336 | > ¿Por qué? Los template strings te dan mayor legibilidad, sintaxis concisa con nuevas líneas apropiadas y capacidades de interpolación. 337 | 338 | ```javascript 339 | // mal 340 | function sayHi(name) { 341 | return 'How are you, ' + name + '?'; 342 | } 343 | 344 | // mal 345 | function sayHi(name) { 346 | return ['How are you, ', name, '?'].join(); 347 | } 348 | 349 | // bien 350 | function sayHi(name) { 351 | return `How are you, ${name}?`; 352 | } 353 | ``` 354 | 355 | - Nunca uses `eval()` en una cadena de texto, abre una caja de Pandora de vulnerabilidades. 356 | 357 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 358 | 359 | 360 | ## Funciones 361 | 362 | - Usa declaración de función en vez de expresiones de función. 363 | 364 | > ¿Por qué? Las declaraciones de función son nombradas, por lo que son más sencillas de identificar en las pilas de llamadas. Además todo el contenido de una declaración de función es *hoisted*, mientras que solo la referencia de una expresión de función es *hoisted*. Esta regla hace posible que siempre se usen [Arrow Functions](#notación-de-funciones-de-flecha) en vez de las funciones de expresión. 365 | 366 | ```javascript 367 | // mal 368 | const foo = function () { 369 | }; 370 | 371 | // bien 372 | function foo() { 373 | } 374 | ``` 375 | 376 | - Nunca declares una función en un bloque que no sea de función (if, while, etc). En vez de ello, asigna la función a una variable. Los navegadores te permitirán hacerlo pero todos ellos lo interpretarán de modo diferente, lo que es lamentable. 377 | 378 | > **Nota:** ECMA-262 define un bloque como una lista de sentencias. Una declaración de función no es una sentencia. [Lee la nota de ECMA-262 sobre este inconveniente](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). 379 | 380 | ```javascript 381 | // mal 382 | if (currentUser) { 383 | function test() { 384 | console.log('Nope.'); 385 | } 386 | } 387 | 388 | // bien 389 | let test; 390 | if (currentUser) { 391 | test = () => { 392 | console.log('Yup.'); 393 | }; 394 | } 395 | ``` 396 | 397 | - Nunca nombres a un parámetro como `arguments`, esto tendrá precedencia sobre el objeto `arguments` que es brindado en cada ámbito de función. 398 | 399 | ```javascript 400 | // mal 401 | function nope(name, options, arguments) { 402 | // ...algo... 403 | } 404 | 405 | // bien 406 | function yup(name, options, args) { 407 | // ...algo... 408 | } 409 | ``` 410 | 411 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 412 | 413 | ## Notación de Funciones de Flecha 414 | 415 | - Cuando debas usar funciones anónimas (como cuando pasas un callback inline), usa la notación de funciones de flecha. 416 | 417 | > ¿Por qué? Crea una versión de la función que ejecuta en el contexto de `this`, lo que usualmente es lo que deseas, además que tiene una sintaxis más concisa. 418 | 419 | > ¿Por qué no? Si tienes una función complicada, debes mover esa lógica fuera de su expresión de función nombrada. 420 | 421 | ```javascript 422 | // mal 423 | [1, 2, 3].map(function (x) { 424 | const y = x + 1; 425 | return x * y; 426 | }); 427 | 428 | // bien 429 | [1, 2, 3].map((x) => { 430 | const y = x + 1; 431 | return x * y; 432 | }); 433 | ``` 434 | 435 | - Si el cuerpo de la función consiste en una sola sentencia retornando una [expresión](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) sin efectos colaterales, omite las llaves y usa el retorno implícito. 436 | De otro modo, mantén las llaves y usa una sentencia de retorno. 437 | 438 | > ¿Por qué? Un edulcorante sintáctico. Se lee bien cuando múltiples funciones están encadenadas entre sí. 439 | 440 | ```javascript 441 | // mal 442 | [1, 2, 3].map(number => { 443 | const nextNumber = number + 1; 444 | `A string containing the ${nextNumber}.`; 445 | }); 446 | 447 | // bien 448 | [1, 2, 3].map(number => `A string containing the ${number}.`); 449 | 450 | // bien 451 | [1, 2, 3].map((number) => { 452 | const nextNumber = number + 1; 453 | return `A string containing the ${nextNumber}.`; 454 | }); 455 | 456 | // bien 457 | [1, 2, 3].map((number, index) => ({ 458 | [index]: number, 459 | })); 460 | 461 | // Sin efectos colaterales para retorno implícito 462 | function foo(callback) { 463 | const val = callback(); 464 | if (val === true) { 465 | // Do something if callback returns true 466 | } 467 | } 468 | 469 | let bool = false; 470 | 471 | // mal 472 | foo(() => bool = true); 473 | 474 | // bien 475 | foo(() => { 476 | bool = true; 477 | }); 478 | ``` 479 | 480 | - En caso que la expresión se expanda en varias líneas, envuélvela en paréntesis para una mejor legibilidad. 481 | 482 | > ¿Por qué? Se observa claramente dónde empieza y termina la función. 483 | 484 | ```javascript 485 | // mal 486 | ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call( 487 | httpMagicObjectWithAVeryLongName, 488 | httpMethod, 489 | ) 490 | ); 491 | 492 | // bien 493 | ['get', 'post', 'put'].map(httpMethod => ( 494 | Object.prototype.hasOwnProperty.call( 495 | httpMagicObjectWithAVeryLongName, 496 | httpMethod, 497 | ) 498 | )); 499 | ``` 500 | 501 | - Si tu función tiene un solo argumento y no usa llaves, omite los paréntesis. De otra forma, siempre incluye paréntesis alrededor de los argumentos por claridad y consistencia. 502 | Nota: es también aceptable siempre usar paréntesis, en cuyo caso usa la [opción de "always"](https://eslint.org/docs/rules/arrow-parens#always) para eslint o no incluyas [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam) para jscs. 503 | 504 | > ¿Por qué? Menos basura visual. 505 | 506 | ```javascript 507 | // mal 508 | [1, 2, 3].map((x) => x * x); 509 | 510 | // bien 511 | [1, 2, 3].map(x => x * x); 512 | 513 | // bien 514 | [1, 2, 3].map(number => ( 515 | `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` 516 | )); 517 | 518 | // mal 519 | [1, 2, 3].map(x => { 520 | const y = x + 1; 521 | return x * y; 522 | }); 523 | 524 | // bien 525 | [1, 2, 3].map((x) => { 526 | const y = x + 1; 527 | return x * y; 528 | }); 529 | ``` 530 | 531 | - Evita confundir la sintaxis de función de flecha (`=>`) con los operadores de comparación (`<=`, `>=`). 532 | 533 | ```javascript 534 | // mal 535 | const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize; 536 | 537 | // mal 538 | const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; 539 | 540 | // bien 541 | const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize); 542 | 543 | // bien 544 | const itemHeight = (item) => { 545 | const { height, largeSize, smallSize } = item; 546 | return height > 256 ? largeSize : smallSize; 547 | }; 548 | ``` 549 | 550 | **[⬆ regresar a la Tabla de Contenido](#tabla-de-contenido)** 551 | 552 | ## Clases y Constructores 553 | 554 | - Siempre usa `class`. Evita manipular `prototype` directamente. 555 | 556 | > ¿Por qué? La sintaxis `class` es más concisa y fácil con la cual lidiar. 557 | 558 | ```javascript 559 | // mal 560 | function Queue(contents = []) { 561 | this._queue = [...contents]; 562 | } 563 | Queue.prototype.pop = function () { 564 | const value = this._queue[0]; 565 | this._queue.splice(0, 1); 566 | return value; 567 | } 568 | 569 | // bien 570 | class Queue { 571 | constructor(contents = []) { 572 | this._queue = [...contents]; 573 | } 574 | pop() { 575 | const value = this._queue[0]; 576 | this._queue.splice(0, 1); 577 | return value; 578 | } 579 | } 580 | ``` 581 | 582 | - Métodos pueden retornar `this` para ayudar con el encadenamiento de métodos (*chaining*). 583 | 584 | ```javascript 585 | // mal 586 | Jedi.prototype.jump = function () { 587 | this.jumping = true; 588 | return true; 589 | }; 590 | 591 | Jedi.prototype.setHeight = function (height) { 592 | this.height = height; 593 | }; 594 | 595 | const luke = new Jedi(); 596 | luke.jump(); // => true 597 | luke.setHeight(20); // => undefined 598 | 599 | // bien 600 | class Jedi { 601 | jump() { 602 | this.jumping = true; 603 | return this; 604 | } 605 | 606 | setHeight(height) { 607 | this.height = height; 608 | return this; 609 | } 610 | } 611 | 612 | const luke = new Jedi(); 613 | 614 | luke.jump() 615 | .setHeight(20); 616 | ``` 617 | 618 | - Está bien escribir un método `toString()` personalizado, solo asegúrate que funcione correctamente y no cause efectos colaterales. 619 | 620 | ```javascript 621 | class Jedi { 622 | constructor(options = {}) { 623 | this.name = options.name || 'no name'; 624 | } 625 | 626 | getName() { 627 | return this.name; 628 | } 629 | 630 | toString() { 631 | return `Jedi - ${this.getName()}`; 632 | } 633 | } 634 | ``` 635 | 636 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 637 | 638 | ## Módulos 639 | 640 | - Siempre usa módulos (`import`/`export`) antes que un sistema de módulos no estándar. Siempre puedes transpilar a tu sistema de módulos preferido. 641 | 642 | > ¿Por qué? Los módulos son el futuro, comencemos a usar el futuro en el presente. 643 | 644 | ```javascript 645 | // mal 646 | const AirbnbStyleGuide = require('./AirbnbStyleGuide'); 647 | module.exports = AirbnbStyleGuide.es6; 648 | 649 | // ok 650 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 651 | export default AirbnbStyleGuide.es6; 652 | 653 | // mejor 654 | import { es6 } from './AirbnbStyleGuide'; 655 | export default es6; 656 | ``` 657 | 658 | - No uses imports con comodines (asterisco). 659 | 660 | > ¿Por qué? Esto te asegura de tener una única exportación por defecto. 661 | 662 | ```javascript 663 | // mal 664 | import * as AirbnbStyleGuide from './AirbnbStyleGuide'; 665 | 666 | // bien 667 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 668 | ``` 669 | 670 | - Y no exportes directamente lo que traigas de un import. 671 | 672 | > ¿Por qué? A pesar que hacer las cosas en una línea es conciso, tener un modo claro de importar y un modo claro de exportar, hace las cosas consistentes. 673 | 674 | ```javascript 675 | // mal 676 | // filename es6.js 677 | export { es6 as default } from './AirbnbStyleGuide'; 678 | 679 | // bien 680 | // filename es6.js 681 | import { es6 } from './AirbnbStyleGuide'; 682 | export default es6; 683 | ``` 684 | 685 | - Solo importa de una ruta en un mismo lugar. 686 | 687 | > ¿Por qué? Tener varias líneas que importan de una misma ruta hace al código difícil de mantener. 688 | 689 | ```javascript 690 | // mal 691 | import foo from 'foo'; 692 | // … some other imports … // 693 | import { named1, named2 } from 'foo'; 694 | 695 | // bien 696 | import foo, { named1, named2 } from 'foo'; 697 | 698 | // bien 699 | import foo, { 700 | named1, 701 | named2, 702 | } from 'foo'; 703 | ``` 704 | 705 | - No exportes las asociaciones (bindings) mutables. 706 | 707 | > ¿Por qué? La mutación debe ser evitada en general, pero en particular cuando se exportan asociaciones (bindings) mutables. Mientras esta técnica puede ser necesaria para algunos casos especiales, en general solo referencias constantes deben ser exportadas. 708 | 709 | ```javascript 710 | // mal 711 | let foo = 3; 712 | export { foo }; 713 | 714 | // bien 715 | const foo = 3; 716 | export { foo }; 717 | ``` 718 | 719 | - En módulos con una única exportación, prefiere la exportación por defecto sobre la exportación nombrada. 720 | 721 | > ¿Por qué? Para forzar a que más archivos solo exporten una sola cosa, lo que es mejor para la legibilidad y mantenibilidad. 722 | 723 | ```javascript 724 | // mal 725 | export function foo() {} 726 | 727 | // bien 728 | export default function foo() {} 729 | ``` 730 | 731 | - Pon todos los `import`s encima de las sentencias de no importación. 732 | 733 | > ¿Por qué? Desde que los `import`s son elevados (hoisted), mantenerlos en el inicio previene comportamientos sorpresivos. 734 | 735 | ```javascript 736 | // mal 737 | import foo from 'foo'; 738 | foo.init(); 739 | 740 | import bar from 'bar'; 741 | 742 | // bien 743 | import foo from 'foo'; 744 | import bar from 'bar'; 745 | 746 | foo.init(); 747 | ``` 748 | 749 | - Imports de multi-línea deben ser indentados como los arreglos multi-línea y literales de objeto. 750 | 751 | > ¿Por qué? Las llaves deben seguir las mismas reglas de indentación como en otros bloques de llaves en la guía de estilos, así como las comas finales. 752 | 753 | ```javascript 754 | // mal 755 | import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; 756 | 757 | // bien 758 | import { 759 | longNameA, 760 | longNameB, 761 | longNameC, 762 | longNameD, 763 | longNameE, 764 | } from 'path'; 765 | ``` 766 | 767 | - No permitas la sintaxis de carga de Webpack en las sentencias de importación de módulos. 768 | 769 | > ¿Por qué? Debido a que usar la sintaxis de Webpack en los imports acopla el código a un ensamblador de módulos. Prefiere usar aquella sintaxis de carga en el archivo de `webpack.config.js`. 770 | 771 | ```javascript 772 | // mal 773 | import fooSass from 'css!sass!foo.scss'; 774 | import barCss from 'style!css!bar.css'; 775 | 776 | // bien 777 | import fooSass from 'foo.scss'; 778 | import barCss from 'bar.css'; 779 | ``` 780 | 781 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 782 | 783 | 784 | ## Propiedades 785 | 786 | - Usa la notación de punto `.` cuando accedas a las propiedades. 787 | 788 | ```javascript 789 | const luke = { 790 | jedi: true, 791 | age: 28 792 | }; 793 | 794 | // mal 795 | const isJedi = luke['jedi']; 796 | 797 | // bien 798 | const isJedi = luke.jedi; 799 | ``` 800 | 801 | - Usa la notación subscript `[]` cuando accedas a las propiedades con una variable. 802 | 803 | ```javascript 804 | const luke = { 805 | jedi: true, 806 | age: 28 807 | }; 808 | 809 | function getProp(prop) { 810 | return luke[prop]; 811 | } 812 | 813 | const isJedi = getProp('jedi'); 814 | ``` 815 | 816 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 817 | 818 | ## Variables 819 | 820 | - Siempre usa `const` para declarar constantes o `let` para declarar variables. No hacerlo resultará en variables globales. Debemos evitar contaminar el espacio global (global namespace). El [Capitán Planeta](https://es.wikipedia.org/wiki/Capit%C3%A1n_Planeta_y_los_planetarios) nos advirtió de eso. 821 | 822 | ```javascript 823 | // mal 824 | superPower = new SuperPower(); 825 | 826 | // bien 827 | const superPower = new SuperPower(); 828 | 829 | o 830 | 831 | // bien 832 | let aPower; 833 | aPower = new SuperPower(); // esto puede cambiar a otro poder posteriormente 834 | ``` 835 | 836 | - Usa una declaración `const` o `let` por variable. 837 | 838 | > ¿Por qué? Es más fácil agregar nuevas declaraciones de variables de este modo, y no tendrás que preocuparte por reemplazar `;` por `,` o introducir diffs de sólo puntuación . 839 | 840 | ```javascript 841 | // mal 842 | const items = getItems(), 843 | goSportsTeam = true, 844 | dragonball = 'z'; 845 | 846 | // mal 847 | // (compara con lo de arriba y encuentra el error) 848 | const items = getItems(), 849 | goSportsTeam = true; 850 | dragonball = 'z'; 851 | 852 | // bien 853 | const items = getItems(); 854 | const goSportsTeam = true; 855 | const dragonball = 'z'; 856 | ``` 857 | 858 | - Agrupa tus `const`s y luego agrupa tus `let`s. 859 | > ¿Por qué? Esto es útil cuando necesites asignar una variable luego dependiendo de una de las variables asignadas previamente. 860 | 861 | ```javascript 862 | // mal 863 | let i, len, dragonball, 864 | items = getItems(), 865 | goSportsTeam = true; 866 | 867 | // mal 868 | let i; 869 | const items = getItems(); 870 | let dragonball; 871 | const goSportsTeam = true; 872 | let len; 873 | 874 | // bien 875 | const goSportsTeam = true; 876 | const items = getItems(); 877 | let dragonball; 878 | let i; 879 | let length; 880 | ``` 881 | 882 | - Asigna las variables cuando las necesites, pero ponlas en un lugar razonable. 883 | > ¿Por qué? `let` y `const` están a nivel de bloque, no a nivel de función. 884 | 885 | ```javascript 886 | // mal - llamada a funcion innecesaria 887 | function checkName(hasName) { 888 | const name = getName(); 889 | 890 | if (hasName === 'test') { 891 | return false; 892 | } 893 | 894 | if (name === 'test') { 895 | this.setName(''); 896 | return false; 897 | } 898 | 899 | return name; 900 | } 901 | 902 | // bien 903 | function checkName(hasName) { 904 | if (hasName === 'test') { 905 | return false; 906 | } 907 | 908 | const name = getName(); 909 | 910 | if (name === 'test') { 911 | this.setName(''); 912 | return false; 913 | } 914 | 915 | return name; 916 | } 917 | ``` 918 | 919 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 920 | 921 | 922 | ## Hoisting 923 | 924 | - Las declaraciones de variables son movidas a la parte superior de su ámbito, sin embargo su asignación no. 925 | 926 | ```javascript 927 | // sabemos que esto no funcionara (asumiendo 928 | // que no hay una variable global notDefined) 929 | function example() { 930 | console.log(notDefined); // => lanza un ReferenceError 931 | } 932 | 933 | // crear una declaracion de variable luego 934 | // que referencies a la variable funcionara 935 | // por el hoisting. Nota: A la asignacion 936 | // del valor `true` no se le aplico hoisting. 937 | function example() { 938 | console.log(declaredButNotAssigned); // => undefined 939 | var declaredButNotAssigned = true; 940 | } 941 | 942 | // El interprete lleva la declaracion de la 943 | // variable a la parte superior de la funcion. 944 | // Eso significa que nuestro ejemplo 945 | // podria ser reescrito como: 946 | function example() { 947 | var declaredButNotAssigned; 948 | console.log(declaredButNotAssigned); // => undefined 949 | declaredButNotAssigned = true; 950 | } 951 | ``` 952 | 953 | - Expresiones de función anónimas hacen hoisting de su nombre de variable, pero no de la asignación de la función. 954 | 955 | ```javascript 956 | function example() { 957 | console.log(anonymous); // => undefined 958 | 959 | anonymous(); // => TypeError anonymous is not a function 960 | 961 | var anonymous = function() { 962 | console.log('anonymous function expression'); 963 | }; 964 | } 965 | ``` 966 | 967 | - Expresiones de función nombradas hacen hoisting de su nombre de variable, pero no del nombre de la función ni del contenido de la función. 968 | 969 | ```javascript 970 | function example() { 971 | console.log(named); // => undefined 972 | 973 | named(); // => TypeError named is not a function 974 | 975 | superPower(); // => ReferenceError superPower is not defined 976 | 977 | var named = function superPower() { 978 | console.log('Flying'); 979 | }; 980 | } 981 | 982 | // lo mismo es cierto cuando el nombre 983 | // de la funcion es igual al nombre de 984 | // la variable. 985 | function example() { 986 | console.log(named); // => undefined 987 | 988 | named(); // => TypeError named is not a function 989 | 990 | var named = function named() { 991 | console.log('named'); 992 | } 993 | } 994 | ``` 995 | 996 | - Las declaraciones de función hacen hoist de su nombre y del contenido de la función. 997 | 998 | ```javascript 999 | function example() { 1000 | superPower(); // => Flying 1001 | 1002 | function superPower() { 1003 | console.log('Flying'); 1004 | } 1005 | } 1006 | ``` 1007 | 1008 | - Para más información lee [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) por [Ben Cherry](http://www.adequatelygood.com/) 1009 | 1010 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1011 | 1012 | 1013 | 1014 | ## Expresiones de comparación e igualdad 1015 | 1016 | - Usa `===` y `!==` en vez de `==` y `!=` respectivamente. 1017 | - Las expresiones condicionales son evaluadas usando coerción con el método `ToBoolean` y siempre obedecen a estas reglas sencillas: 1018 | 1019 | + **Objects** son evaluados como **true** (se considera así al objeto vacío `{}` y arreglos sin contenido `[]`) 1020 | + **Undefined** es evaluado como **false** 1021 | + **Null** es evaluado como **false** 1022 | + **Booleans** son evaluados como **el valor del booleano** 1023 | + **Numbers** son evaluados como **false** si su valor es **+0**, **-0**, o **NaN**, de otro modo **true** 1024 | + **Strings** son evaluados como **false** si es una cadena de texto vacía `''`, de otro modo son **true** 1025 | 1026 | ```javascript 1027 | if ([0] && []) { 1028 | // true 1029 | // un arreglo es un objeto (incluso uno vacío), los objetos son evaluados como true 1030 | } 1031 | ``` 1032 | 1033 | - Usa atajos. 1034 | 1035 | ```javascript 1036 | // mal 1037 | if (name !== '') { 1038 | // ...cosas... 1039 | } 1040 | 1041 | // bien 1042 | if (name) { 1043 | // ...cosas... 1044 | } 1045 | 1046 | // mal 1047 | if (collection.length > 0) { 1048 | // ...cosas... 1049 | } 1050 | 1051 | // bien 1052 | if (collection.length) { 1053 | // ...cosas... 1054 | } 1055 | ``` 1056 | 1057 | - Para más información revisa [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) por Angus Croll 1058 | 1059 | - Usa llaves para crear bloques en cláusulas `case` y `default` que contengan 1060 | declaraciones léxicas (e.g. `let`, `const`, `function` y `class`). 1061 | 1062 | > ¿Por qué? La declaración léxica es visible en todo el bloque `switch` 1063 | pero solo se inicializa al ser asignado, lo que solo ocurre cuando el bloque 1064 | `case` donde es declarado es alcanzado. Esto causa problemas cuando 1065 | múltiples bloques `case` intentan definir la misma variable. 1066 | 1067 | 1068 | ```javascript 1069 | // mal 1070 | switch (foo) { 1071 | case 1: 1072 | let x = 1; 1073 | break; 1074 | case 2: 1075 | const y = 2; 1076 | break; 1077 | case 3: 1078 | function f() {} 1079 | break; 1080 | default: 1081 | class C {} 1082 | } 1083 | 1084 | // bien 1085 | switch (foo) { 1086 | case 1: { 1087 | let x = 1; 1088 | break; 1089 | } 1090 | case 2: { 1091 | const y = 2; 1092 | break; 1093 | } 1094 | case 3: { 1095 | function f() {} 1096 | break; 1097 | } 1098 | case 4: 1099 | bar(); 1100 | break; 1101 | default: { 1102 | class C {} 1103 | } 1104 | } 1105 | ``` 1106 | 1107 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1108 | 1109 | 1110 | ## Bloques 1111 | 1112 | - Usa llaves con todos los bloques de múltiples líneas. 1113 | 1114 | ```javascript 1115 | // mal 1116 | if (test) 1117 | return false; 1118 | 1119 | // bien 1120 | if (test) return false; 1121 | 1122 | // bien 1123 | if (test) { 1124 | return false; 1125 | } 1126 | 1127 | // mal 1128 | function() { return false; } 1129 | 1130 | // bien 1131 | function() { 1132 | return false; 1133 | } 1134 | ``` 1135 | 1136 | - Si estás usando bloques de muchas líneas con ```if``` y ```else```, pon el ```else``` en la misma línea que el ```if```. 1137 | 1138 | ```javascript 1139 | // mal 1140 | if (test) { 1141 | thing1(); 1142 | thing2(); 1143 | } 1144 | else { 1145 | thing3(); 1146 | } 1147 | 1148 | // bien 1149 | if (test) { 1150 | thing1(); 1151 | thing2(); 1152 | } else { 1153 | thing3(); 1154 | } 1155 | ``` 1156 | 1157 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1158 | 1159 | 1160 | ## Comentarios 1161 | 1162 | - Usa `/** ... */` para comentarios de múltiples líneas. Incluye una descripción, especificación de tipos y valores para todos los parámetros y valores de retorno. 1163 | 1164 | ```javascript 1165 | // mal 1166 | // make() returns a new element 1167 | // based on the passed in tag name 1168 | // 1169 | // @param {String} tag 1170 | // @return {Element} element 1171 | function make(tag) { 1172 | 1173 | // ...stuff... 1174 | 1175 | return element; 1176 | } 1177 | 1178 | // bien 1179 | /** 1180 | * make() returns a new element 1181 | * based on the passed in tag name 1182 | * 1183 | * @param {String} tag 1184 | * @return {Element} element 1185 | */ 1186 | function make(tag) { 1187 | 1188 | // ...stuff... 1189 | 1190 | return element; 1191 | } 1192 | ``` 1193 | 1194 | - Usa `//` para comentarios de una sola línea. Ubica los comentarios de una sola línea encima de la sentencia comentada. Deja una línea en blanco antes del comentario, a menos que sea la primera línea de un bloque. 1195 | 1196 | ```javascript 1197 | // mal 1198 | const active = true; // is current tab 1199 | 1200 | // bien 1201 | // is current tab 1202 | const active = true; 1203 | 1204 | // mal 1205 | function getType() { 1206 | console.log('fetching type...'); 1207 | // set the default type to 'no type' 1208 | const type = this._type || 'no type'; 1209 | 1210 | return type; 1211 | } 1212 | 1213 | // bien 1214 | function getType() { 1215 | console.log('fetching type...'); 1216 | 1217 | // set the default type to 'no type' 1218 | const type = this._type || 'no type'; 1219 | 1220 | return type; 1221 | } 1222 | ``` 1223 | 1224 | - Agregando a tus comentarios los prefijos `FIXME` o `TODO`, ayudará a otros desarrolladores a entender rápidamente si estás apuntando a un problema que precisa ser revisado o si estás sugiriendo una solución al problema que debería ser implementado. Estos son diferentes a comentarios regulares en el sentido que requieren alguna acción. Las acciones son `FIXME -- necesito resolver esto` o `TODO -- necesita implementarse`. 1225 | 1226 | - Usa `// FIXME:` para anotar problemas. 1227 | 1228 | ```javascript 1229 | class Calculator extends Abacus { 1230 | constructor() { 1231 | super(); 1232 | 1233 | // FIXME: shouldn't use a global here 1234 | total = 0; 1235 | } 1236 | } 1237 | ``` 1238 | 1239 | - Usa `// TODO:` para anotar soluciones a los problemas. 1240 | 1241 | ```javascript 1242 | class Calculator extends Abacus { 1243 | constructor() { 1244 | super(); 1245 | 1246 | // TODO: total should be configurable by an options param 1247 | this.total = 0; 1248 | } 1249 | } 1250 | ``` 1251 | 1252 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1253 | 1254 | 1255 | ## Espacios en blanco 1256 | 1257 | - Usa indentaciones blandas (sin TAB) establecidas en dos espacios. 1258 | 1259 | ```javascript 1260 | // mal 1261 | function foo() { 1262 | ∙∙∙∙const name; 1263 | } 1264 | 1265 | // mal 1266 | function bar() { 1267 | ∙const name; 1268 | } 1269 | 1270 | // bien 1271 | function baz() { 1272 | ∙∙const name; 1273 | } 1274 | ``` 1275 | - Deja un espacio antes de la llave de apertura. 1276 | 1277 | ```javascript 1278 | // mal 1279 | function test(){ 1280 | console.log('test'); 1281 | } 1282 | 1283 | // bien 1284 | function test() { 1285 | console.log('test'); 1286 | } 1287 | 1288 | // mal 1289 | dog.set('attr',{ 1290 | age: '1 year', 1291 | breed: 'Bernese Mountain Dog' 1292 | }); 1293 | 1294 | // bien 1295 | dog.set('attr', { 1296 | age: '1 year', 1297 | breed: 'Bernese Mountain Dog' 1298 | }); 1299 | ``` 1300 | 1301 | - Deja un espacio antes del paréntesis de apertura en las sentencias de control (```if```, ```while```, etc.). No dejes espacios antes de la lista de argumentos en las invocaciones y declaraciones de funciones. 1302 | ```javascript 1303 | // mal 1304 | if(isJedi) { 1305 | fight (); 1306 | } 1307 | 1308 | // bien 1309 | if (isJedi) { 1310 | fight(); 1311 | } 1312 | 1313 | // mal 1314 | function fight () { 1315 | console.log ('Swooosh!'); 1316 | } 1317 | 1318 | // bien 1319 | function fight() { 1320 | console.log('Swooosh!'); 1321 | } 1322 | ``` 1323 | 1324 | - Separa a los operadores con espacios. 1325 | ```javascript 1326 | // mal 1327 | const x=y+5; 1328 | 1329 | // bien 1330 | const x = y + 5; 1331 | ``` 1332 | 1333 | - Deja una línea en blanco al final del archivo. 1334 | 1335 | ```javascript 1336 | // mal 1337 | (function(global) { 1338 | // ...algo... 1339 | })(this); 1340 | ``` 1341 | 1342 | ```javascript 1343 | // mal 1344 | (function(global) { 1345 | // ...algo... 1346 | })(this);↵ 1347 | ↵ 1348 | 1349 | ``` 1350 | 1351 | ```javascript 1352 | // bien 1353 | (function(global) { 1354 | // ...algo... 1355 | })(this);↵ 1356 | 1357 | ``` 1358 | 1359 | - Usa indentación cuando uses métodos largos con 'chaining' (más de dos métodos encadenados). Emplea un punto adelante en cada nueva línea, lo que enfatiza que es un método llamado no una nueva sentencia. 1360 | 1361 | ```javascript 1362 | // mal 1363 | $('#items').find('.selected').highlight().end().find('.open').updateCount(); 1364 | 1365 | // mal 1366 | $('#items'). 1367 | find('.selected'). 1368 | highlight(). 1369 | end(). 1370 | find('.open'). 1371 | updateCount(); 1372 | 1373 | // bien 1374 | $('#items') 1375 | .find('.selected') 1376 | .highlight() 1377 | .end() 1378 | .find('.open') 1379 | .updateCount(); 1380 | 1381 | // mal 1382 | const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) 1383 | .attr('width', (radius + margin) * 2).append('svg:g') 1384 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 1385 | .call(tron.led); 1386 | 1387 | // bien 1388 | const leds = stage.selectAll('.led') 1389 | .data(data) 1390 | .enter().append('svg:svg') 1391 | .class('led', true) 1392 | .attr('width', (radius + margin) * 2) 1393 | .append('svg:g') 1394 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 1395 | .call(tron.led); 1396 | ``` 1397 | 1398 | - Deja una línea en blanco luego de los bloques y antes de la siguiente sentencia. 1399 | 1400 | ```javascript 1401 | // mal 1402 | if (foo) { 1403 | return bar; 1404 | } 1405 | return baz; 1406 | 1407 | // bien 1408 | if (foo) { 1409 | return bar; 1410 | } 1411 | 1412 | return baz; 1413 | 1414 | // mal 1415 | const obj = { 1416 | foo() { 1417 | }, 1418 | bar() { 1419 | } 1420 | }; 1421 | return obj; 1422 | 1423 | // bien 1424 | const obj = { 1425 | foo() { 1426 | }, 1427 | 1428 | bar() { 1429 | } 1430 | }; 1431 | 1432 | return obj; 1433 | 1434 | // mal 1435 | const arr = [ 1436 | function foo() { 1437 | }, 1438 | function bar() { 1439 | }, 1440 | ]; 1441 | return arr; 1442 | 1443 | // bien 1444 | const arr = [ 1445 | function foo() { 1446 | }, 1447 | 1448 | function bar() { 1449 | }, 1450 | ]; 1451 | 1452 | return arr; 1453 | ``` 1454 | 1455 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1456 | 1457 | ## Comas 1458 | 1459 | - Comas al inicio de línea: **Nop.** 1460 | 1461 | ```javascript 1462 | // mal 1463 | const story = [ 1464 | once 1465 | , upon 1466 | , aTime 1467 | ]; 1468 | 1469 | // bien 1470 | const story = [ 1471 | once, 1472 | upon, 1473 | aTime, 1474 | ]; 1475 | 1476 | // mal 1477 | const hero = { 1478 | firstName: 'Ada' 1479 | , lastName: 'Lovelace' 1480 | , birthYear: 1815 1481 | , superPower: 'strength' 1482 | }; 1483 | 1484 | // bien 1485 | const hero = { 1486 | firstName: 'Ada', 1487 | lastName: 'Lovelace', 1488 | birthYear: 1815, 1489 | superPower: 'computers', 1490 | }; 1491 | ``` 1492 | 1493 | - Coma adicional al final: **Sip.** 1494 | > ¿Por qué? Esto lleva a diferenciales en git más claros. Además los transpiladores como Babel removerán la coma del final en el código transpilado lo que significa que no te tendrás que preocupar del [problema de la coma adicional al final](es5/README.md#commas) en navegadores antiguos. 1495 | 1496 | ```javascript 1497 | // mal - git diff sin coma adicional al final 1498 | const hero = { 1499 | firstName: 'Florence', 1500 | - lastName: 'Nightingale' 1501 | + lastName: 'Nightingale', 1502 | + inventorOf: ['coxcomb chart', 'modern nursing'] 1503 | }; 1504 | 1505 | // bien - git diff con coma adicional al final 1506 | const hero = { 1507 | firstName: 'Florence', 1508 | lastName: 'Nightingale', 1509 | + inventorOf: ['coxcomb chart', 'modern nursing'], 1510 | }; 1511 | 1512 | // mal 1513 | const hero = { 1514 | firstName: 'Dana', 1515 | lastName: 'Scully' 1516 | }; 1517 | 1518 | const heroes = [ 1519 | 'Batman', 1520 | 'Superman' 1521 | ]; 1522 | 1523 | // bien 1524 | const hero = { 1525 | firstName: 'Dana', 1526 | lastName: 'Scully', 1527 | }; 1528 | 1529 | const heroes = [ 1530 | 'Batman', 1531 | 'Superman', 1532 | ]; 1533 | ``` 1534 | 1535 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1536 | 1537 | 1538 | ## Puntos y Comas 1539 | 1540 | - **Sip.** 1541 | 1542 | ```javascript 1543 | // mal 1544 | (function () { 1545 | const name = 'Skywalker' 1546 | return name 1547 | })() 1548 | 1549 | // bien 1550 | (() => { 1551 | const name = 'Skywalker'; 1552 | return name; 1553 | }()); 1554 | 1555 | // bien, pero arcaico (evita que la funcion se vuelva un argumento 1556 | // cuando dos archivos con IIFEs sean concatenados) 1557 | ;(() => { 1558 | const name = 'Skywalker'; 1559 | return name; 1560 | }()); 1561 | ``` 1562 | 1563 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1564 | 1565 | 1566 | ## Casting de Tipos y Coerción 1567 | 1568 | - Ejecuta coerción al inicio de una sentencia. 1569 | - Strings: 1570 | 1571 | ```javascript 1572 | // => this.reviewScore = 9; 1573 | 1574 | // mal 1575 | const totalScore = this.reviewScore + ''; // invoca a this.reviewScore.valueOf() 1576 | 1577 | // mal 1578 | const totalScore = this.reviewScore.toString(); // no se garantiza que retorne una cadena de texto 1579 | 1580 | // bien 1581 | const totalScore = String(this.reviewScore); 1582 | ``` 1583 | 1584 | - Números: Usa `Number` para el casting de tipo y `parseInt` siempre con la base numérica para el casting de textos. 1585 | 1586 | ```javascript 1587 | const inputValue = '4'; 1588 | 1589 | // mal 1590 | const val = new Number(inputValue); 1591 | 1592 | // mal 1593 | const val = +inputValue; 1594 | 1595 | // mal 1596 | const val = inputValue >> 0; 1597 | 1598 | // mal 1599 | const val = parseInt(inputValue); 1600 | 1601 | // bien 1602 | const val = Number(inputValue); 1603 | 1604 | // bien 1605 | const val = parseInt(inputValue, 10); 1606 | ``` 1607 | 1608 | - Si por alguna razón estás haciendo algo salvaje y `parseInt` es un cuello de botella por lo que necesitaste usar Bitshift por [razones de desempeño](http://jsperf.com/coercion-vs-casting/3), deja un comentario explicando la razón y resumen de lo que estás haciendo. 1609 | 1610 | ```javascript 1611 | // bien 1612 | /** 1613 | * parseInt was the reason my code was slow. 1614 | * Bitshifting the String to coerce it to a 1615 | * Number made it a lot faster. 1616 | */ 1617 | const val = inputValue >> 0; 1618 | ``` 1619 | 1620 | > **Nota:** Ten mucho cuidado al hacer operaciones de Bitshift. En Javascript los números son representados como [valores de 64-bit](http://es5.github.io/#x4.3.19), sin embargo las operaciones de Bitshift siempre retornan un entero de 32-bits ([fuente](http://es5.github.io/#x11.7)). Bitshift puede presentarnos un comportamiento inesperado para valores enteros mayores a 32 bits. [Discusión](https://github.com/airbnb/javascript/issues/109). El mayor entero con signo de 32 bits es 2,147,483,647: 1621 | ```javascript 1622 | 2147483647 >> 0 //=> 2147483647 1623 | 2147483648 >> 0 //=> -2147483648 1624 | 2147483649 >> 0 //=> -2147483647 1625 | ``` 1626 | 1627 | - Booleans: 1628 | 1629 | ```javascript 1630 | const age = 0; 1631 | 1632 | // mal 1633 | const hasAge = new Boolean(age); 1634 | 1635 | // bien 1636 | const hasAge = Boolean(age); 1637 | 1638 | // bien 1639 | const hasAge = !!age; 1640 | ``` 1641 | 1642 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1643 | 1644 | 1645 | ## Convenciones de nomenclatura 1646 | 1647 | - Evita nombres de una sola letra. Sé descriptivo con tus nombres. 1648 | 1649 | ```javascript 1650 | // mal 1651 | function q() { 1652 | // ...algo... 1653 | } 1654 | 1655 | // bien 1656 | function query() { 1657 | // ...algo... 1658 | } 1659 | ``` 1660 | 1661 | - Usa camelCase cuando nombres tus objetos, funciones e instancias. 1662 | 1663 | ```javascript 1664 | // mal 1665 | const OBJEcttsssss = {}; 1666 | const this_is_my_object = {}; 1667 | const o = {}; 1668 | function c() {} 1669 | 1670 | // bien 1671 | var thisIsMyObject = {}; 1672 | function thisIsMyFunction() {} 1673 | ``` 1674 | 1675 | - Usa PascalCase cuando nombres constructores o clases. 1676 | 1677 | ```javascript 1678 | // mal 1679 | function user(options) { 1680 | this.name = options.name; 1681 | } 1682 | 1683 | const bad = new user({ 1684 | name: 'nope' 1685 | }); 1686 | 1687 | // bien 1688 | class User { 1689 | constructor(options) { 1690 | this.name = options.name; 1691 | } 1692 | } 1693 | 1694 | const good = new User({ 1695 | name: 'yup', 1696 | }); 1697 | ``` 1698 | 1699 | - No uses prefijos ni sufijos de guiones bajo. 1700 | > ¿Por qué? JavaScript no tiene el concepto de privacidad en términos de propiedades o métodos. A pesar que un guión bajo como prefijo es una convención común para indicar que son "privados", la realidad es que estas propiedades son absolutamente públicas, y por ello, parte de tu contrato público de API. La convención del prefijo de guión bajo podría orientar a los desarrolladores a pensar erróneamente que un cambio a aquellos no será de impacto o que los tests no son necesarios. 1701 | 1702 | ```javascript 1703 | // mal 1704 | this.__firstName__ = 'Panda'; 1705 | this.firstName_ = 'Panda'; 1706 | this._firstName = 'Panda'; 1707 | 1708 | 1709 | // bien 1710 | this.firstName = 'Panda'; 1711 | ``` 1712 | 1713 | - Nunca guardes referencias a `this`. Usa funciones arrow o la función [#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) 1714 | 1715 | ```javascript 1716 | // mal 1717 | function() { 1718 | const self = this; 1719 | return function() { 1720 | console.log(self); 1721 | }; 1722 | } 1723 | 1724 | // mal 1725 | function() { 1726 | const that = this; 1727 | return function() { 1728 | console.log(that); 1729 | }; 1730 | } 1731 | 1732 | // bien 1733 | function foo() { 1734 | return () => { 1735 | console.log(this); 1736 | }; 1737 | } 1738 | ``` 1739 | 1740 | - El nombre del archivo base debe corresponder exactamente con el nombre de su export por defecto. 1741 | 1742 | ```javascript 1743 | // contenido archivo 1 1744 | class CheckBox { 1745 | // ... 1746 | } 1747 | export default CheckBox; 1748 | 1749 | // contenido archivo 2 1750 | export default function fortyTwo() { return 42; } 1751 | 1752 | // contenido archivo 3 1753 | export default function insideDirectory() {} 1754 | 1755 | // en algún otro archivo 1756 | // mal 1757 | import CheckBox from './checkBox'; // importacion/exportacion PascalCase, nombre de archivo camelCase 1758 | import FortyTwo from './FortyTwo'; // importacion/nombre de archivo PascalCase, exportacion camelCase 1759 | import InsideDirectory from './InsideDirectory'; // importacion/nombre de archivo PascalCase, exportacion camelCase 1760 | 1761 | // mal 1762 | import CheckBox from './check_box'; // importacion/exportacion PascalCase, nombre de archivo snake_case 1763 | import forty_two from './forty_two'; // importacion/nombre de archivo snake_case, exportacion camelCase 1764 | import inside_directory from './inside_directory'; // importacion snake_case, exportacion camelCase 1765 | import index from './inside_directory/index'; // requiere el archivo de index explicitamente 1766 | import insideDirectory from './insideDirectory/index'; // requiere el archivo de index explicitamente 1767 | 1768 | // bien 1769 | import CheckBox from './CheckBox'; // importacion/exportacion/nombre de archivo PascalCase 1770 | import fortyTwo from './fortyTwo'; // importacion/exportacion/nombre de archivo camelCase 1771 | import insideDirectory from './insideDirectory'; // importacion/exportacion/nombre directorio/archivo "index" implícito 1772 | // ^ soporta tanto insideDirectory.js e insideDirectory/index.js 1773 | 1774 | ``` 1775 | 1776 | - Usa camelCase cuando exportes por defecto una función. Tu nombre de archivo debe ser idéntico al nombre de tu función. 1777 | 1778 | ```javascript 1779 | function makeStyleGuide() { 1780 | } 1781 | 1782 | export default makeStyleGuide; 1783 | ``` 1784 | 1785 | - Usa camelCase cuando exportes un objeto constructor / clase / singleton / librería de función / esqueleto. 1786 | ```javascript 1787 | const AirbnbStyleGuide = { 1788 | es6: { 1789 | } 1790 | }; 1791 | 1792 | export default AirbnbStyleGuide; 1793 | ``` 1794 | 1795 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1796 | 1797 | 1798 | ## Funciones de Acceso 1799 | 1800 | - Funciones de acceso para las propiedades no son requeridas. 1801 | - No uses getters/setters de JavaScript ya que causan efectos colaterales no esperados y son difíciles de probar, mantener y razonar. En vez de ello, si creas funciones de acceso usa ```getVal()``` y ```setVal('hello')```. 1802 | 1803 | ```javascript 1804 | // Maintainable-JavaScript-Nicholas-C-Zakas 1805 | class Dragon { 1806 | get age() { 1807 | // ... 1808 | } 1809 | 1810 | set age(value) { 1811 | // ... 1812 | } 1813 | } 1814 | 1815 | // bien 1816 | class Dragon { 1817 | getAge() { 1818 | // ... 1819 | } 1820 | 1821 | setAge(value) { 1822 | // ... 1823 | } 1824 | } 1825 | ``` 1826 | 1827 | - Si la propiedad es un booleano, usa ```isVal()``` o ```hasVal()```. 1828 | 1829 | ```javascript 1830 | // mal 1831 | if (!dragon.age()) { 1832 | return false; 1833 | } 1834 | 1835 | // bien 1836 | if (!dragon.hasAge()) { 1837 | return false; 1838 | } 1839 | ``` 1840 | 1841 | - Está bien crear funciones ```get()``` y ```set()```, pero sé consistente. 1842 | 1843 | ```javascript 1844 | class Jedi { 1845 | constructor(options = {}) { 1846 | const lightsaber = options.lightsaber || 'blue'; 1847 | this.set('lightsaber', lightsaber); 1848 | } 1849 | 1850 | set(key, val) { 1851 | this[key] = val; 1852 | } 1853 | 1854 | get(key) { 1855 | return this[key]; 1856 | } 1857 | } 1858 | ``` 1859 | 1860 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1861 | 1862 | 1863 | ## Eventos 1864 | 1865 | - Cuando envíes paquetes de datos a los eventos (ya sea con eventos del DOM o algo propietario como los eventos de Backbone), pasa un mapa en vez de un valor directo. Esto permitirá a un próximo colaborador a agregar más datos al paquete de datos sin que tenga que encontrar o actualizar un handler para cada evento. Por ejemplo, en vez de: 1866 | 1867 | ```js 1868 | // mal 1869 | $(this).trigger('listingUpdated', listing.id); 1870 | 1871 | ... 1872 | 1873 | $(this).on('listingUpdated', (e, listingId) => { 1874 | // hacer algo con listingId 1875 | }); 1876 | ``` 1877 | 1878 | prefiere: 1879 | 1880 | ```js 1881 | // bien 1882 | $(this).trigger('listingUpdated', { listingId : listing.id }); 1883 | 1884 | ... 1885 | 1886 | $(this).on('listingUpdated', (e, data) => { 1887 | // hacer algo con data.listingId 1888 | }); 1889 | ``` 1890 | 1891 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1892 | 1893 | ## jQuery 1894 | 1895 | - Nombre las variables de objetos jQuery con un prefijo `$`. 1896 | 1897 | ```javascript 1898 | // mal 1899 | const sidebar = $('.sidebar'); 1900 | 1901 | // bien 1902 | const $sidebar = $('.sidebar'); 1903 | ``` 1904 | 1905 | - Guarde en variables los lookups de jQuery que se necesiten posteriormente. 1906 | 1907 | ```javascript 1908 | // mal 1909 | function setSidebar() { 1910 | $('.sidebar').hide(); 1911 | 1912 | // ...algo... 1913 | 1914 | $('.sidebar').css({ 1915 | 'background-color': 'pink' 1916 | }); 1917 | } 1918 | 1919 | // bien 1920 | function setSidebar() { 1921 | const $sidebar = $('.sidebar'); 1922 | $sidebar.hide(); 1923 | 1924 | // ...algo... 1925 | 1926 | $sidebar.css({ 1927 | 'background-color': 'pink' 1928 | }); 1929 | } 1930 | ``` 1931 | 1932 | - Para consultas de elementos DOM usa el modo Cascada `$('.sidebar ul')` o parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) 1933 | - Usa `find` solo con consultas guardadas en variables previamente. 1934 | 1935 | ```javascript 1936 | // mal 1937 | $('ul', '.sidebar').hide(); 1938 | 1939 | // mal 1940 | $('.sidebar').find('ul').hide(); 1941 | 1942 | // bien 1943 | $('.sidebar ul').hide(); 1944 | 1945 | // bien 1946 | $('.sidebar > ul').hide(); 1947 | 1948 | // bien 1949 | $sidebar.find('ul'); 1950 | ``` 1951 | 1952 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1953 | 1954 | 1955 | ## Compatibilidad con ECMAScript 5 1956 | 1957 | - Revisa la [tabla de compatibilidad](http://kangax.github.com/es5-compat-table/) de ES5 de [Kangax](https://twitter.com/kangax/). 1958 | 1959 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1960 | 1961 | ## Estilos de EcmaScript6+ (ES 2015+) 1962 | 1963 | - A continuación, un conjunto de enlaces hacia los estilos para las nuevas características de ES6: 1964 | 1965 | 1. [Notación Funciones de Flecha](#arrow-functions) 1966 | 1. [Clases](#classes--constructors) 1967 | 1. [Declaración abreviada para objeto](#es6-object-shorthand) 1968 | 1. [Declaración de objeto concisa](#es6-object-concise) 1969 | 1. [Propiedades computadas de objeto](#es6-computed-properties) 1970 | 1. [Plantillas de texto](#es6-template-literals) 1971 | 1. [Destructuring](#destructuring) 1972 | 1. [Parámetros por defecto](#es6-default-parameters) 1973 | 1. [Rest](#es6-rest) 1974 | 1. [Spreads de arreglos](#es6-array-spreads) 1975 | 1. [Let y Const](#references) 1976 | 1. [Iteradores y Generadores](#iterators-and-generators) 1977 | 1. [Módulos](#modules) 1978 | 1979 | - No uses [las propuestas de TC39](https://github.com/tc39/proposals) puesto que aún no han llegado a la tercera etapa. 1980 | 1981 | > ¿Por qué? [No están finalizadas](https://tc39.github.io/process-document/), y están sujetas a cambios o reescritas completamente. Vamos a usar JavaScript y las propuestas aún no son JavaScript. 1982 | 1983 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 1984 | 1985 | ## Pruebas 1986 | 1987 | - **Sip**. 1988 | 1989 | ```javascript 1990 | function foo() { 1991 | return true; 1992 | } 1993 | ``` 1994 | 1995 | - **No, but seriously**: 1996 | - Cualquiera que sea el framework de testing que emplees, ¡deberías escribir tests! 1997 | - Esfuérzate por escribir funciones pequeñas y puras, además de minimizar las posibles mutaciones que pudiesen ocurrir. 1998 | - Sé cuidados con los stubs y los mocks - pueden hacer tus tests más frágiles. 1999 | - Usamos principalmente [`mocha`](https://www.npmjs.com/package/mocha) en Airbnb. [`tape`](https://www.npmjs.com/package/tape) es también usado ocasionalmente para módulos pequeños y separados. 2000 | - 100% de cobertura de pruebas es una buena meta a perseguir, a pesar que no es siempre práctico conseguirlo. 2001 | - Cuando corrijas una incidencia (bug), _escribe una prueba de regresión_. Una incidencia sin una prueba de regresión es casi seguro que volverá a ocurrir en el futuro. 2002 | 2003 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 2004 | 2005 | ## Desempeño 2006 | 2007 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) 2008 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) 2009 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) 2010 | - [Bang Function](http://jsperf.com/bang-function) 2011 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) 2012 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) 2013 | - [Long String Concatenation](http://jsperf.com/ya-string-concat) 2014 | - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta) 2015 | - Loading... 2016 | 2017 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 2018 | 2019 | 2020 | ## Recursos 2021 | 2022 | **Learning ES6** 2023 | 2024 | - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html) 2025 | - [ExploringJS](http://exploringjs.com/) 2026 | - [Tabla de compatibilidad de ES6](https://kangax.github.io/compat-table/es6/) 2027 | - [Vistazo comprensivo de las nuevas características de ES6](http://es6-features.org/) 2028 | 2029 | **Lee esto** 2030 | 2031 | - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) 2032 | 2033 | **Tools** 2034 | 2035 | Code Style Linters 2036 | - [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc) 2037 | - [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) 2038 | 2039 | **Otras guías de estilo** 2040 | 2041 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) (Guía de Estilo de Javascript de Google) 2042 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) (Lineamientos de Estilo con el núcleo de jQuery) 2043 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) (Idiomatic Javascript: Principios de Escritura Consistente) 2044 | 2045 | **Otros estilos** 2046 | 2047 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen (Nomenclatura en funciones anidadas) 2048 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) (Callbacks condicionales) 2049 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) (Convenciones Populares de Programación con Javascript en Github) 2050 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman (Múltiples sentencias var en JavaScript, no superfluas) 2051 | 2052 | **Lecturas más profundas** 2053 | 2054 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll (Entendiendo los Closures de JavaScript) 2055 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer (JavaScript Básico para el programador impaciente) 2056 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz (Podrías no necesitar jQuery) 2057 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban (Características de ES6) 2058 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock (Lineamientos para el Frontend) 2059 | 2060 | **Libros** 2061 | 2062 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford (JavaScript: Las Buenas Partes) 2063 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov (Patrones JavaScript) 2064 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz (Patrones de Diseño Avanzados en Javascript) 2065 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders (Sitios Web de Alto Desempeño: Conocimiento Esencial para los Ingenieros de Capa de Presentación) 2066 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas (JavaScript Mantenible) 2067 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw (Aplicaciones Web JavaScript) 2068 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig (Técnicas Avanzadas JavaScript) 2069 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch (Increíble Node.js: JavaScript en todas partes) 2070 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault (Secretos del JavaScript Ninja) 2071 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg (JavaScript Humano) 2072 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy (Superhéroe.js) 2073 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 2074 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov (JavaScript de Terceros) 2075 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman (JavaScript Efectivo: 68 modos específicos para elevar el poder de JavaScript) 2076 | - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke (JavaScript Elocuente) 2077 | - [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson (No sabes JS: ES6 y más allá) 2078 | 2079 | **Blogs** 2080 | 2081 | - [DailyJS](http://dailyjs.com/) 2082 | - [JavaScript Weekly](http://javascriptweekly.com/) 2083 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) 2084 | - [Bocoup Weblog](http://weblog.bocoup.com/) 2085 | - [Adequately Good](http://www.adequatelygood.com/) 2086 | - [NCZOnline](http://www.nczonline.net/) 2087 | - [Perfection Kills](http://perfectionkills.com/) 2088 | - [Ben Alman](http://benalman.com/) 2089 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 2090 | - [Dustin Diaz](http://dustindiaz.com/) 2091 | - [nettuts](http://net.tutsplus.com/?s=javascript) 2092 | 2093 | **Podcasts** 2094 | 2095 | - [JavaScript Air](https://javascriptair.com/) 2096 | - [JavaScript Jabber](http://devchat.tv/js-jabber/) 2097 | 2098 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 2099 | 2100 | ## En la cancha 2101 | 2102 | Esta es una lista de las organizaciones que están usando esta guía de estilo. Envíanos un pull request o abre un issue y te agregaremos a la lista. 2103 | 2104 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 2105 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 2106 | - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript) 2107 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 2108 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 2109 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 2110 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 2111 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) 2112 | - **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 2113 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 2114 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 2115 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) 2116 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 2117 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 2118 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) 2119 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) 2120 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) 2121 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) 2122 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) 2123 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) 2124 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 2125 | - **Userify**: [userify/javascript](https://github.com/userify/javascript) 2126 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 2127 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 2128 | 2129 | ## Traducciones 2130 | 2131 | Esta guía de estilo es también disponible en otros lenguajes: 2132 | 2133 | - ![us](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/United-States.png) **Inglés (original)**: [airbnb/javascript](https://github.com/airbnb/javascript) 2134 | - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Portugués Brasileño**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) 2135 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Búlgaro**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 2136 | - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalán**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) 2137 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chino (Tradicional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 2138 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chino (Simplificado)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) 2139 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **Francés**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) 2140 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **Alemán**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) 2141 | - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italiano**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) 2142 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japonés**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) 2143 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Coreano**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) 2144 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polaco**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 2145 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Ruso**: [uprock/javascript](https://github.com/uprock/javascript) 2146 | - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Tailandés**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) 2147 | - ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnamita**: [giangpii/javascript-style-guide](https://github.com/giangpii/javascript-style-guide) 2148 | ## La guía de la Guía de Estilos de Javascript 2149 | 2150 | - [Referencia](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 2151 | 2152 | ## Charla con nosotros sobre Javascript 2153 | - Encuéntranos en [gitter](https://gitter.im/airbnb/javascript). 2154 | 2155 | ## Colaboradores 2156 | 2157 | - [Vea a los colaboradores](https://github.com/airbnb/javascript/graphs/contributors) 2158 | 2159 | 2160 | ## Licencia 2161 | 2162 | (The MIT License) 2163 | 2164 | Copyright (c) 2014-2016 Airbnb 2165 | 2166 | Permission is hereby granted, free of charge, to any person obtaining 2167 | a copy of this software and associated documentation files (the 2168 | 'Software'), to deal in the Software without restriction, including 2169 | without limitation the rights to use, copy, modify, merge, publish, 2170 | distribute, sublicense, and/or sell copies of the Software, and to 2171 | permit persons to whom the Software is furnished to do so, subject to 2172 | the following conditions: 2173 | 2174 | The above copyright notice and this permission notice shall be 2175 | included in all copies or substantial portions of the Software. 2176 | 2177 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 2178 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2179 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2180 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 2181 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2182 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2183 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2184 | 2185 | **[[⬆ regresar a la Tabla de Contenido]](#tabla-de-contenido)** 2186 | 2187 | ## Enmiendas 2188 | 2189 | Te recomendamos hacer fork de esta guía y cambiar las reglas para que se adecúen a la guía de estilos de tu equipo. Abajo podrás encontrar algunas enmiendas a la guía de estilos. Esto te permitirá actualizar periódicamente tu guía de estilos sin tener que lidiar con conflictos al hacer merge. 2190 | 2191 | # }; 2192 | --------------------------------------------------------------------------------