Photo by Pankaj Patel on Unsplash
Guía de Estilo de JavaScript de Airbnb()
Un enfoque mayormente razonable para JavaScript.
Otras Guías de Estilo
Traducido de Airbnb JavaScript Style Guide.
Tipos (Types)
- 1.1 Primitivos (Primitives): Accedes a los tipos primitivos directamente.
stringnumberbooleannullundefined
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
- 1.2 Complejos (Complex): Accedes a los tipos complejos por referencia (by reference).
objectarrayfunction
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
Referencias (References)
- 2.1 Usa
constpara todas tus referencias; evita usarvar. eslint:prefer-const,no-const-assign
¿Por qué? Esto asegura que no puedas reasignar tus referencias, lo que puede llevar a errores y código difícil de comprender.
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- 2.2 Si debes reasignar referencias, usa
leten lugar devar. eslint:no-varjscs:disallowVar
¿Por qué?
lettiene alcance de bloque (block-scoped), mientras quevartiene alcance de función (function-scoped).
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
- 2.3 Ten en cuenta que tanto
letcomoconsttienen alcance de bloque.
// const y let solo existen dentro del bloque donde se definen.
{
let a = 1;
const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
Objetos (Objects)
- 3.1 Usa la sintaxis literal para la creación de objetos. eslint rules:
no-new-object.
// bad
const item = new Object();
// good
const item = {};
- 3.2 No sigas usando palabras reservadas como claves. No funcionará en IE8. Más info. Sin embargo, está bien usarlas en módulos ES6 y código del lado del servidor. jscs:
disallowIdentifierNames
// bad
const superman = {
default: { clark: 'kent' },
private: true,
};
// good
const superman = {
defaults: { clark: 'kent' },
hidden: true,
};
- 3.3 Usa sinónimos legibles en lugar de palabras reservadas. jscs:
disallowIdentifierNames
// bad
const superman = {
class: 'alien',
};
// bad
const superman = {
klass: 'alien',
};
// good
const superman = {
type: 'alien',
};
- 3.4 Usa nombres de propiedades calculados (computed property names) al crear objetos con nombres de propiedades dinámicos.
¿Por qué? Te permiten definir todas las propiedades del objeto en un solo lugar.
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
- 3.5 Usa la abreviatura de métodos de objeto (object method shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
- 3.6 Usa la abreviatura de valores de propiedad (property value shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
¿Por qué? Es más corto y descriptivo.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 3.7 Agrupa tus abreviaturas al principio de tu declaración de objeto.
¿Por qué? Es más fácil saber qué propiedades están usando la abreviatura.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
- 3.8 Solo pon entre comillas las propiedades que sean identificadores inválidos. eslint:
quote-propsjscs:disallowQuotedKeysInObjects
¿Por qué? En general, lo consideramos subjetivamente más fácil de leer. Mejora el resaltado de sintaxis y también es más fácil de optimizar por muchos motores JS.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
Arreglos (Arrays)
- 4.1 Usa la sintaxis literal para la creación de arreglos. eslint:
no-array-constructor
// bad
const items = new Array();
// good
const items = [];
- 4.2 Usa Array#push en lugar de la asignación directa para agregar elementos a un arreglo.
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- 4.3 Usa la propagación de arreglos (array spreads)
...para copiar arreglos.
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
- 4.4 Para convertir un objeto similar a un arreglo (array-like object) en un arreglo, usa Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
- 4.5 Usa declaraciones de retorno en las devoluciones de llamada de los métodos de arreglo. Está bien omitir el retorno si el cuerpo de la función consiste en una sola declaración siguiendo 8.2. eslint:
array-callback-return
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map(x => x + 1);
// bad
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = memo.concat(item);
});
// good
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = flatten;
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
Desestructuración (Destructuring)
- 5.1 Usa la desestructuración de objetos cuando accedas y uses múltiples propiedades de un objeto. jscs:
requireObjectDestructuring
¿Por qué? La desestructuración te evita crear referencias temporales para esas propiedades.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- 5.2 Usa la desestructuración de arreglos. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
- 5.3 Usa la desestructuración de objetos para múltiples valores de retorno, no la desestructuración de arreglos.
¿Por qué? Puedes agregar nuevas propiedades o cambiar el orden de las cosas sin romper los sitios de llamada.
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, right } = processInput(input);
Cadenas (Strings)
- 6.1 Usa comillas simples
''para cadenas. eslint:quotesjscs:validateQuoteMarks
// bad
const name = "Capt. Janeway";
// good
const name = 'Capt. Janeway';
- 6.2 Las cadenas que hacen que la línea supere los 100 caracteres no deben escribirse en varias líneas usando concatenación de cadenas.
- 6.3 Nota: Si se usa en exceso, la concatenación de cadenas largas puede afectar el rendimiento. jsPerf & Discusión.
// bad
const 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.';
// bad
const 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.';
// good
const 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.';
- 6.4 Al construir cadenas programáticamente, usa plantillas de cadena (template strings) en lugar de concatenación. eslint:
prefer-templatetemplate-curly-spacingjscs:requireTemplateStrings
¿Por qué? Las plantillas de cadena te dan una sintaxis legible y concisa con líneas nuevas y funciones de interpolación de cadenas adecuadas.
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- 6.5 Nunca uses
eval()en una cadena, abre demasiadas vulnerabilidades.
Funciones (Functions)
- 7.1 Usa declaraciones de función (function declarations) en lugar de expresiones de función (function expressions). jscs:
requireFunctionDeclarations
¿Por qué? Las declaraciones de función tienen nombre, por lo que son más fáciles de identificar en los seguimientos de pila (stack traces). Además, las declaraciones de función se elevan (hoisted), mientras que las expresiones de función no. Esta regla hace que sea fácil para Arrow Functions reemplazar completamente las expresiones de función.
// bad
const foo = function () {
};
// good
function foo() {
}
- 7.2 IIFE: eslint:
wrap-iifejscs:requireParenthesesAroundIIFE
¿Por qué? Una IIFE es una unidad única: envolver la función y su invocación entre paréntesis lo hace claro. Ten en cuenta que en un mundo con módulos, casi no necesitas IIFE.
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
-
7.3 Nunca declares una función en un bloque que no sea de función (if, while, etc). Asigna la función a una variable en su lugar. Los navegadores te permitirán hacerlo, pero todos lo interpretan de manera diferente. eslint:
no-loop-func -
7.4 Nota: ECMA-262 define un
bloquecomo una lista de declaraciones. Una declaración de función no es una declaración. Lee la nota de ECMA-262 sobre este problema.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
- 7.5 Nunca nombres un parámetro
arguments. Esto tendrá prioridad sobre el objetoargumentsque se le da a cada alcance de función.
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
- 7.6 Nunca uses
arguments, opta por usar la sintaxis rest...en su lugar.prefer-rest-params
¿Por qué?
...es explícito sobre qué argumentos quieres extraer. Además, los argumentos rest son un Array real, y no simplemente Array-like comoarguments.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 7.7 Usa la sintaxis de parámetros predeterminados en lugar de mutar los argumentos de la función.
// really bad
function handleThings(opts) {
// No! We shouldn't mutate function arguments.
// Double bad: if opts is false it will be set to an object which may
// be what you want but it can cause subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 7.8 Evita los efectos secundarios con parámetros predeterminados.
¿Por qué? Son confusos de entender.
var b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
- 7.9 Pon siempre los parámetros por defecto en último lugar.
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
- 7.10 Nunca uses el constructor de Función para crear una nueva función.
¿Por qué? Crear una función de esta manera evalúa una cadena de forma similar a eval(), lo que abre vulnerabilidades.
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
- 7.11 Espaciado en la firma de una función.
¿Por qué? La consistencia es buena, y no deberías tener que agregar o quitar espacio al agregar o quitar un nombre.
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
- 7.12 Nunca mutes parámetros. eslint:
no-param-reassign
¿Por qué? Manipular objetos pasados como parámetros puede causar efectos secundarios no deseados en el llamador original.
// bad
function f1(obj) {
obj.key = 1;
};
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};
- 7.13 Nunca reasignes parámetros. eslint:
no-param-reassign
¿Por qué? Reasignar parámetros puede llevar a un comportamiento inesperado, especialmente al acceder al objeto
arguments. También puede causar problemas de optimización, especialmente en V8.
```javascript
// bad
function f1(a) {
a = 1;
}
function f2(a) {
if (!a) { a = 1; }
}
// good
function f3(a) {
const b = a || 1;
}
function f4(a = 1) {
}
```
Funciones de Flecha (Arrow Functions)
- 8.1 Cuando debas usar una expresión de función (como al pasar una función anónima), usa la notación de función de flecha. eslint:
prefer-arrow-callback,arrow-spacingjscs:requireArrowFunctions
¿Por qué? Crea una versión de la función que se ejecuta en el contexto de
this, que es generalmente lo que quieres, y es una sintaxis más concisa.
¿Por qué no? Si tienes una función bastante compleja, podrías mover esa lógica a su propia declaración de función nombrada.
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.2 Si el cuerpo de la función consta de una sola declaración que devuelve una expresión sin efectos secundarios, omite las llaves y usa el retorno implícito. De lo contrario, mantén las llaves y usa una declaración
return. eslint:arrow-parens,arrow-body-stylejscs:disallowParenthesesAroundArrowParam,requireShorthandArrowFunctions
¿Por qué? Azúcar sintáctico (Syntactic sugar). Es más legible cuando múltiples funciones se encadenan juntas.
¿Por qué no? Si planeas devolver un objeto.
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map(number => `A string containing the ${number}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
- 8.3 En caso de que la expresión se extienda a lo largo de varias líneas, envuélvela entre paréntesis para una mejor legibilidad.
¿Por qué? Muestra claramente dónde empieza y termina la función.
// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
`${number} became much longer. So we needed to break it over multiple ` +
'lines.'
);
// good
[1, 2, 3].map(number => (
`As time went by, the string containing the ${number} became much ` +
'longer. So we needed to break it over multiple lines.'
));
- 8.4 Si tu función toma un solo argumento y no usa llaves, omite los paréntesis. De lo contrario, incluye siempre paréntesis alrededor de los argumentos. eslint:
arrow-parensjscs:disallowParenthesesAroundArrowParam
¿Por qué? Menos desorden visual.
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we’ve broken it ` +
'over multiple lines!'
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.5 Evita confundir la sintaxis de función de flecha (
=>) con operadores de comparación (<=,>=). eslint:no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; }
Constructores (Constructors)
- 9.1 Usa siempre
class. Evita manipularprototypedirectamente.
¿Por qué? La sintaxis
classes más concisa y más fácil de razonar.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
- 9.2 Usa
extendspara la herencia.
¿Por qué? Es una forma integrada de heredar la funcionalidad del prototipo sin romper
instanceof.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
- 9.3 Los métodos pueden devolver
thispara ayudar con el encadenamiento de métodos (method chaining).
// bad
Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function (height) {
this.height = height;
};
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// good
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
- 9.4 Está bien escribir un método toString() personalizado, solo asegúrate de que funcione correctamente y no cause efectos secundarios.
class Jedi {
constructor(options = {}) {
this.name = options.name || 'no name';
}
getName() {
return this.name;
}
toString() {
return `Jedi - ${this.getName()}`;
}
}
- 9.5 Las clases tienen un constructor predeterminado si no se especifica uno. Un constructor vacío o uno que simplemente delega a una clase padre es innecesario.
no-useless-constructor
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
Módulos (Modules)
- 10.1 Utiliza siempre módulos (
import/export) en lugar de un sistema de módulos no estándar. Siempre puedes transpirar a tu sistema de módulos preferido.
¿Por qué? Los módulos son el futuro, empecemos a usar el futuro ahora.
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 10.2 No uses imports con comodines (wildcard imports).
¿Por qué? Esto asegura que tengas un solo default export.
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
- 10.3 Y no exportes directamente desde un import.
¿Por qué? Aunque escribirlo en una línea es conciso, tener una forma clara de importar y una forma clara de exportar hace que las cosas sean consistentes.
// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
Iteradores y Generadores (Iterators and Generators)
- 11.1 No uses iteradores. Prefiere las funciones de orden superior de JavaScript como
map()yreduce()en lugar de bucles comofor-of. eslint:no-iterator
¿Por qué? Esto hace cumplir nuestra regla de inmutabilidad. Tratar con funciones puras que devuelven valores es más fácil de razonar que los efectos secundarios.
eslint rules: no-iterator.
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
- 11.2 No uses generadores por ahora.
¿Por qué? No se transpilan bien a ES5 todavía.
Propiedades (Properties)
- 12.1 Usa la notación de punto (dot notation) al acceder a propiedades. eslint:
dot-notationjscs:requireDotNotation
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
- 12.2 Usa la notación de corchetes
[]al acceder a propiedades con una variable.
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
Variables (Variables)
- 13.1 Siempre usa
constoletpara declarar variables. No hacerlo resultará en variables globales. Queremos evitar contaminar el espacio de nombres global (global namespace). El Capitán Planeta nos advirtió sobre eso.
// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();
- 13.2 Usa una declaración
constoletpor variable. eslint:one-varjscs:disallowMultipleVarDecl
¿Por qué? Es más fácil agregar nuevas declaraciones de variables de esta manera, y nunca tienes que preocuparte por cambiar un
;por una,o introducir diferencias solo de puntuación.
// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, notice the error)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
- 13.3 Agrupa todos tus
consty luego agrupa todos tuslet.
¿Por qué? Esto es útil cuando más tarde necesites asignar una variable dependiendo de una de las variables asignadas previamente.
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
- 13.4 Asigna variables donde las necesites, pero colócalas en un lugar razonable.
¿Por qué?
letyconsttienen alcance de bloque y no de función.
// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
Hoisting
- 14.1 Las declaraciones
varse elevan (hoisted) a la parte superior de su alcance, pero su asignación no. Las declaracionesconstyletson bendecidas con un nuevo concepto llamado Zonas Muertas Temporales (TDZ). Es importante saber por qué typeof ya no es seguro.
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// The interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// using const and let
function example() {
console.log(declaredButNotAssigned); // => throws a ReferenceError
console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
const declaredButNotAssigned = true;
}
- 14.2 Las expresiones de función anónimas elevan su nombre de variable, pero no la asignación de la función.
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
- 14.3 Las expresiones de función con nombre elevan el nombre de la variable, no el nombre de la función ni el cuerpo de la función.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
}
}
- 14.4 Las declaraciones de función elevan su nombre y el cuerpo de la función.
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
- Para más información, consulta JavaScript Scoping & Hoisting por Ben Cherry.
Operadores de Comparación e Igualdad (Comparison Operators & Equality)
-
15.2 Las declaraciones condicionales como
ifevalúan su expresión usando coerción con el método abstractoToBooleany siempre siguen estas reglas simples:
- Objects se evalúan como true
- Undefined se evalúa como false
- Null se evalúa como false
- Booleans se evalúan como el valor del booleano
- Numbers se evalúan como false si son +0, -0, o NaN, de lo contrario true
- Strings se evalúan como false si es una cadena vacía
'', de lo contrario true
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
- 15.3 Usa atajos.
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
- 15.4 Para más información, consulta Truth Equality and JavaScript por Angus Croll.
- 15.5 Usa llaves para crear bloques en las cláusulas
caseydefaultque contienen declaraciones léxicas (por ejemplo,let,const,functionyclass).
¿Por qué? Las declaraciones léxicas son visibles en todo el bloque
switchpero solo se inicializan cuando se asignan, lo que solo sucede cuando se alcanza sucase. Esto causa problemas cuando múltiples cláusulascaseintentan definir lo mismo.
eslint rules: no-case-declarations.
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
- 15.7 Los ternarios no deben anidarse y generalmente deben ser expresiones de una sola línea.
eslint rules: no-nested-ternary.
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// better
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
- 15.8 Evita las declaraciones ternarias innecesarias.
eslint rules: no-unneeded-ternary.
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
Bloques (Blocks)
- 16.1 Usa llaves con todos los bloques de varias líneas.
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
- 16.2 Si estás usando bloques de varias líneas con
ifyelse, ponelseen la misma línea que la llave de cierre del bloqueif. eslint:brace-stylejscs:disallowNewlineBeforeBlockStatements
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
Sentencias de Control (Control Statements)
- 17.1 En caso de que su declaración de control (
if,whileetc.) se vuelva demasiado larga o exceda la longitud máxima de línea, cada condición (agrupada) podría ponerse en una nueva línea. El operador lógico debe comenzar la línea.
¿Por qué? Requerir operadores al comienzo de la línea mantiene los operadores alineados y sigue un patrón similar al encadenamiento de métodos. Esto también mejora la legibilidad al hacer que la lógica compleja sea más fácil de seguir visualmente.
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
- 17.2 No uses operadores de selección en lugar de declaraciones de control.
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
Comentarios (Comments)
- 18.1 Usa
/** ... */para comentarios de varias líneas. Incluye una descripción, especifica tipos y valores para todos los parámetros y valores de retorno.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param {String} tag
* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
- 18.2 Usa
//para comentarios de una sola línea. Coloca los comentarios de una sola línea en una nueva línea sobre el sujeto del comentario. Pon una línea vacía antes del comentario a menos que esté en la primera línea de un bloque.
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
-
18.3 Prefijar tus comentarios con
FIXMEoTODOayuda a otros desarrolladores a entender rápidamente si estás señalando un problema que necesita ser revisado o si estás sugiriendo una solución que necesita ser implementada. Estos son diferentes de los comentarios regulares porque son accionables. Las acciones sonFIXME: -- need to figure this outoTODO: -- need to implement. -
18.4 Usa
// FIXME:para anotar problemas.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
- 18.5 Usa
// TODO:para anotar soluciones a problemas.
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
Espacios en blanco (Whitespace)
- 19.1 Usa tabulaciones suaves (carácter de espacio) establecidas en 2 espacios. eslint:
indentjscs:validateIndentation
// bad
function foo() {
∙∙∙∙const name;
}
// bad
function bar() {
∙const name;
}
// good
function baz() {
∙∙const name;
}
- 19.2 Coloca 1 espacio antes de la llave de apertura. eslint:
space-before-blocksjscs:requireSpaceBeforeBlockStatements
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});
- 19.3 Coloca 1 espacio antes del paréntesis de apertura en las declaraciones de control (
if,whileetc.). No pongas espacio entre la lista de argumentos y el nombre de la función en las llamadas y declaraciones de funciones. eslint:space-after-keywords,space-before-keywordsjscs:requireSpaceAfterKeywords
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
- 19.4 Separa los operadores con espacios. eslint:
space-infix-opsjscs:requireSpaceBeforeBinaryOperators,requireSpaceAfterBinaryOperators
// bad
const x=y+5;
// good
const x = y + 5;
- 19.5 Termina los archivos con un solo carácter de nueva línea.
// bad
(function (global) {
// ...stuff...
})(this);
// bad
(function (global) {
// ...stuff...
})(this);↵
↵
// good
(function (global) {
// ...stuff...
})(this);↵
- 19.6 Usa indentación al hacer cadenas de métodos largas (más de 2 cadenas de métodos). Usa un punto al principio, lo que enfatiza que la línea es una llamada a un método, no una nueva declaración. eslint:
newline-per-chained-callno-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
.call(tron.led);
// good
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
.call(tron.led);
// good
const leds = stage.selectAll('.led').data(data);
- 19.7 Deja una línea en blanco después de los bloques y antes de la siguiente declaración. jscs:
requirePaddingNewLinesAfterBlocks
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
- 19.8 No rellenes tus bloques con líneas en blanco. eslint:
padded-blocksjscs:disallowPaddingNewlinesInBlocks
// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
- 19.9 No agregues espacios dentro de los paréntesis. eslint:
space-in-parensjscs:disallowSpacesInsideParentheses
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
- 19.10 No agregues espacios dentro de los corchetes. eslint:
array-bracket-spacingjscs:disallowSpacesInsideArrayBrackets
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
- 19.11 Agrega espacios dentro de las llaves. eslint:
object-curly-spacingjscs: [disallowSpacesInsideObjectBrackets](http://jscs.info/rule/
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
- 19.12 Evita líneas de más de 100 caracteres (incluyendo espacios en blanco). eslint:
max-lenjscs:maximumLineLength
¿Por qué? Esto asegura la legibilidad y el mantenimiento.
// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
'Whatever wizard constrains a helpful ally. The counterpart ascends!';
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
Comas (Commas)
- 20.1 Comas principales (Leading commas): No. eslint:
comma-stylejscs:requireCommaBeforeLineBreak
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
- 20.2 Coma final adicional (Additional trailing comma): Sí. eslint:
comma-danglejscs:requireTrailingComma
¿Por qué? Esto lleva a diferencias de git (git diffs) más limpias. Además, los transpiladores como Babel eliminarán la coma final adicional en el código transpilado, lo que significa que no tienes que preocuparte por el problema de la coma final en los navegadores heredados.
// bad - git diff without trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb graph', 'modern nursing']
};
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
Punto y coma (Semicolons)
- 21.1 Sí. eslint:
semijscs:requireSemicolons
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(() => {
const name = 'Skywalker';
return name;
}());
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
const name = 'Skywalker';
return name;
}());
Conversión de Tipos y Coerción (Type Casting & Coercion)
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
- 22.3 Números (Numbers): Usa
Numberpara la conversión de tipos yparseIntsiempre con una base para analizar cadenas. eslint:radix
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
- 22.4 Si por alguna razón estás haciendo algo salvaje y
parseIntes tu cuello de botella y necesitas usar Bitshift por razones de rendimiento, deja un comentario explicando por qué y qué estás haciendo.
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
- 22.5 Nota: Ten cuidado al usar operaciones de bitshift. Los números se representan como valores de 64 bits, pero las operaciones de bitshift siempre devuelven un entero de 32 bits (fuente). El bitshift puede llevar a un comportamiento inesperado para valores enteros mayores de 32 bits. Discusión. El entero con signo de 32 bits más grande es 2,147,483,647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
- 22.6 Booleanos (Booleans):
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// good
const hasAge = !!age;
Convenciones de Nomenclatura (Naming Conventions)
- 23.1 Evita nombres de una sola letra. Sé descriptivo con tu nomenclatura.
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
- 23.2 Usa camelCase al nombrar objetos, funciones e instancias. eslint:
camelcasejscs:requireCamelCaseOrUpperCaseIdentifiers
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 23.3 Usa PascalCase solo al nombrar constructores o clases. eslint:
new-capjscs:requireCapitalizedConstructors
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
- 23.4 Usa un guion bajo
_al principio al nombrar propiedades privadas. eslint:no-underscore-danglejscs:disallowDanglingUnderscores
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
- 23.5 No guardes referencias a
this. Usa funciones de flecha o Function#bind. jscs:disallowNodeTypes
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
- 23.6 Si tu archivo exporta una sola clase, el nombre de tu archivo debe coincidir exactamente con el nombre de tu clase.
// file contents
class CheckBox {
// ...
}
export default CheckBox;
// in some other file
// bad
import CheckBox from './checkBox';
// bad
import CheckBox from './check_box';
// good
import CheckBox from './CheckBox';
- 23.7 Usa camelCase cuando exportes por defecto una función. El nombre de tu archivo debe ser idéntico al nombre de tu función.
function makeStyleGuide() {
}
export default makeStyleGuide;
- 23.8 Usa PascalCase cuando exportes un singleton / biblioteca de funciones / objeto simple.
const AirbnbStyleGuide = {
es6: {
}
};
export default AirbnbStyleGuide;
Accesores (Accessors)
- 24.1 Las funciones de acceso para propiedades no son obligatorias.
- 24.2 No uses getters/setters de JavaScript ya que causan efectos secundarios inesperados y son difíciles de probar, mantener y razonar. En su lugar, si creas funciones de acceso, usa getVal() y setVal(‘hello’).
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
- 24.3 Si la propiedad es un booleano, usa
isVal()ohasVal().
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
- 24.4 Está bien crear funciones get() y set(), pero sé consistente.
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}
Eventos (Events)
- 25.1 Al adjuntar cargas de datos (payloads) a eventos (ya sea eventos DOM o algo más propietario como eventos de Backbone), pasa un hash en lugar de un valor sin procesar. Esto permite que un colaborador posterior agregue más datos a la carga útil del evento sin encontrar y actualizar cada controlador para el evento. Por ejemplo, en lugar de:
// bad
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', (e, listingId) => {
// do something with listingId
});
prefiere:
// good
$(this).trigger('listingUpdated', { listingId: listing.id });
...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingId
});
jQuery
- 26.1 Prefija los objetos jQuery con
$. jscs:requireDollarBeforejQueryAssignment
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
- 26.2 Caché de búsquedas jQuery (jQuery lookups).
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
- 26.3 Para consultas DOM, usa encadenamiento
$('.sidebar ul')o padre > hijo$('.sidebar > ul'). jsPerf - 26.4 Usa
findcon consultas de objeto jQuery con alcance.
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
Compatibilidad con ECMAScript 5 (ECMAScript 5 Compatibility)
- 27.1 Consulta la tabla de compatibilidad de ES5 de Kangax.
Estilos de ECMAScript 6 (ECMAScript 6 Styles)
- 28.1 Esta es una colección de enlaces a las diversas características de ES6.
- Arrow Functions
- Classes
- Object Shorthand
- Object Concise
- Computed Object Properties
- Template Strings
- Destructuring
- Default Parameters
- Rest
- Array Spreads
- Let and Const
- Iterators and Generators
- Modules
Biblioteca Estándar (Standard Library)
La Biblioteca Estándar contiene algunas utilidades que están rotas pero se mantienen por razones heredadas.
- 29.1 Usa
Number.isNaNen lugar deisNaN.
¿Por qué?
isNaNconvierte los valores no numéricos en números, devolviendo verdadero para cualquier cosa que se convierta a NaN. Si este comportamiento es deseado, hazlo explícito.
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
- 29.2 Usa
Number.isFiniteen lugar deisFinite.
¿Por qué?
isFiniteconvierte los valores no numéricos en números, devolviendo verdadero para cualquier cosa que se convierta a un número finito. Si este comportamiento es deseado, hazlo explícito.
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
Pruebas (Testing)
- 30.1 Sí.
function foo() {
return true;
}
- 30.2 No, en serio:
- ¡No importa qué marco de prueba uses, deberías estar escribiendo pruebas!
- Trata de escribir muchas funciones puras pequeñas y minimiza dónde ocurren las mutaciones.
- Ten cuidado con los stubs y mocks: pueden hacer que tus pruebas sean más frágiles.
- Usamos principalmente
mochaen Airbnb.tapetambién se usa ocasionalmente para módulos pequeños y aislados. - El 100% de cobertura de prueba es un buen objetivo por el que luchar, incluso si no siempre es práctico alcanzarlo.
- Cada vez que arregles un error, escribe una prueba de regresión. Un error arreglado sin una prueba de regresión es casi seguro que se romperá de nuevo en el futuro.
Rendimiento (Performance)
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading…
Recursos (Resources)
Aprender ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Lectura Obligatoria
Herramientas
- Code Style Linters
Otras Guías de Estilo
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Otros Estilos
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Lectura Adicional
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Libros
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript…
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts
En el mundo real (In the Wild)
Esta es una lista de organizaciones que utilizan esta guía de estilo. Envíanos un pull request o un issue y te añadiremos a la lista.
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Avalara: avalara/javascript
- Avant: avantcredit/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- Brainshark: brainshark/javascript
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- Kinetica Solutions: kinetica/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StudentSphere: studentsphere/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
Traducción (Translation)
Esta guía de estilo también está disponible en otros idiomas:
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): sivan/javascript-style-guide
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javacript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Vietnamese: f1remoon/javascript-style-guide
Guía de Guías de Estilo de JavaScript (The JavaScript Style Guide Guide)
Chatea con nosotros sobre JavaScript
- Encuéntranos en gitter.
Colaboradores (Contributors)
Licencia (License)
(The MIT License)
Copyright (c) 2014-2016 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Enmiendas (Amendments)
Te animamos a bifurcar esta guía y cambiar las reglas para que se ajusten a la guía de estilo de tu equipo. A continuación, puedes enumerar algunas enmiendas a la guía de estilo. Esto te permite actualizar periódicamente tu guía de estilo sin tener que lidiar con conflictos de fusión (merge conflicts).