Un enfoque mayoritariamente razonable para JavaScript
Nota : esta guía asume que estás usando Babel y requiere que uses babel-preset-airbnb o su equivalente. También supone que estás instalando shims/polyfills en tu aplicación, con airbnb-browser-shims o equivalente.
Esta guía también está disponible en otros idiomas. Ver traducción
Otras guías de estilo
1.1 Primitivas : cuando accedes a un tipo primitivo, trabajas directamente sobre su valor.
string
number
boolean
null
undefined
symbol
bigint
const foo = 1 ;
let bar = foo ;
bar = 9 ;
console . log ( foo , bar ) ; // => 1, 9
1.2 Complejo : Cuando accedes a un tipo complejo trabajas sobre una referencia a su valor.
object
array
function
const foo = [ 1 , 2 ] ;
const bar = foo ;
bar [ 0 ] = 9 ;
console . log ( foo [ 0 ] , bar [ 0 ] ) ; // => 9, 9
⬆ volver arriba
2.1 Utilice const
para todas sus referencias; Evite usar var
. eslint: prefer-const
, no-const-assign
¿Por qué? Esto garantiza que no pueda reasignar sus referencias, lo que puede generar 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 debe reasignar referencias, use let
en lugar de var
. eslint: no-var
¿Por qué?
let
tiene un alcance de bloque en lugar de un alcance de función comovar
.
// bad
var count = 1 ;
if ( true ) {
count += 1 ;
}
// good, use the let.
let count = 1 ;
if ( true ) {
count += 1 ;
}
2.3 Tenga en cuenta que tanto let
como const
tienen un alcance de bloque, mientras que var
tiene un alcance de función.
// const and let only exist in the blocks they are defined in.
{
let a = 1 ;
const b = 1 ;
var c = 1 ;
}
console . log ( a ) ; // ReferenceError
console . log ( b ) ; // ReferenceError
console . log ( c ) ; // Prints 1
En el código anterior, puede ver que hacer referencia a
y b
producirá un ReferenceError, mientras que c
contiene el número. Esto se debe a que a
y b
tienen un alcance de bloque, mientras que c
tiene un alcance de la función contenedora.
⬆ volver arriba
3.1 Utilice la sintaxis literal para la creación de objetos. eslint: no-new-object
// bad
const item = new Object ( ) ;
// good
const item = { } ;
3.2 Utilice nombres de propiedades calculados al crear objetos con nombres de propiedades dinámicas.
¿Por qué? Le permiten definir todas las propiedades de un 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.3 Utilice la abreviatura del método de objeto. eslint: object-shorthand
// bad
const atom = {
value : 1 ,
addValue : function ( value ) {
return atom . value + value ;
} ,
} ;
// good
const atom = {
value : 1 ,
addValue ( value ) {
return atom . value + value ;
} ,
} ;
3.4 Utilice la taquigrafía del valor de la propiedad. eslint: object-shorthand
¿Por qué? Es más breve y descriptivo.
const lukeSkywalker = 'Luke Skywalker' ;
// bad
const obj = {
lukeSkywalker : lukeSkywalker ,
} ;
// good
const obj = {
lukeSkywalker ,
} ;
3.5 Agrupe sus propiedades abreviadas al comienzo de su declaración de objeto.
¿Por qué? Es más fácil saber qué propiedades utilizan la taquigrafía.
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.6 Sólo cite propiedades que sean identificadores no válidos. eslint: quote-props
¿Por qué? En general lo consideramos subjetivamente más fácil de leer. Mejora el resaltado de sintaxis y muchos motores JS también lo optimizan más fácilmente.
// bad
const bad = {
'foo' : 3 ,
'bar' : 4 ,
'data-blah' : 5 ,
} ;
// good
const good = {
foo : 3 ,
bar : 4 ,
'data-blah' : 5 ,
} ;
3.7 No llame directamente a los métodos Object.prototype
, como hasOwnProperty
, propertyIsEnumerable
e isPrototypeOf
. eslint: no-prototype-builtins
¿Por qué? Estos métodos pueden estar ocultos por las propiedades del objeto en cuestión (consulte
{ hasOwnProperty: false }
) o el objeto puede ser un objeto nulo (Object.create(null)
). En los navegadores modernos que admiten ES2022, o con un polyfill como https://npmjs.com/object.hasown,Object.hasOwn
también se puede utilizar como alternativa aObject.prototype.hasOwnProperty.call
.
// bad
console . log ( object . hasOwnProperty ( key ) ) ;
// good
console . log ( Object . prototype . hasOwnProperty . call ( object , key ) ) ;
// better
const has = Object . prototype . hasOwnProperty ; // cache the lookup once, in module scope.
console . log ( has . call ( object , key ) ) ;
// best
console . log ( Object . hasOwn ( object , key ) ) ; // only supported in browsers that support ES2022
/* or */
import has from 'has' ; // https://www.npmjs.com/package/has
console . log ( has ( object , key ) ) ;
/* or */
console . log ( Object . hasOwn ( object , key ) ) ; // https://www.npmjs.com/package/object.hasown
3.8 Prefiera la sintaxis de extensión de objetos sobre Object.assign
para objetos de copia superficial. Utilice la sintaxis del parámetro de resto del objeto para obtener un nuevo objeto con ciertas propiedades omitidas. eslint: prefer-object-spread
// very bad
const original = { a : 1 , b : 2 } ;
const copy = Object . assign ( original , { c : 3 } ) ; // this mutates `original` ಠ_ಠ
delete copy . a ; // so does this
// bad
const original = { a : 1 , b : 2 } ;
const copy = Object . assign ( { } , original , { c : 3 } ) ; // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a : 1 , b : 2 } ;
const copy = { ... original , c : 3 } ; // copy => { a: 1, b: 2, c: 3 }
const { a , ... noA } = copy ; // noA => { b: 2, c: 3 }
⬆ volver arriba
4.1 Utilice la sintaxis literal para la creación de matrices. eslint: no-array-constructor
// bad
const items = new Array ( ) ;
// good
const items = [ ] ;
4.2 Utilice Array#push en lugar de asignación directa para agregar elementos a una matriz.
const someStack = [ ] ;
// bad
someStack [ someStack . length ] = 'abracadabra' ;
// good
someStack . push ( 'abracadabra' ) ;
4.3 Utilice extensiones de matrices ...
para copiar matrices.
// bad
const len = items . length ;
const itemsCopy = [ ] ;
let i ;
for ( i = 0 ; i < len ; i += 1 ) {
itemsCopy [ i ] = items [ i ] ;
}
// good
const itemsCopy = [ ... items ] ;
4.4 Para convertir un objeto iterable en una matriz, use spreads ...
en lugar de Array.from
const foo = document . querySelectorAll ( '.foo' ) ;
// good
const nodes = Array . from ( foo ) ;
// best
const nodes = [ ... foo ] ;
4.5 Utilice Array.from
para convertir un objeto similar a una matriz en una matriz.
const arrLike = { 0 : 'foo' , 1 : 'bar' , 2 : 'baz' , length : 3 } ;
// bad
const arr = Array . prototype . slice . call ( arrLike ) ;
// good
const arr = Array . from ( arrLike ) ;
4.6 Utilice Array.from
en lugar de spread ...
para mapear iterables, porque evita crear una matriz intermedia.
// bad
const baz = [ ... foo ] . map ( bar ) ;
// good
const baz = Array . from ( foo , bar ) ;
4.7 Utilice declaraciones de retorno en devoluciones de llamadas de métodos de matriz. Está bien omitir el retorno si el cuerpo de la función consta de una sola declaración que devuelve una expresión sin efectos secundarios, según 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 - no returned value means `acc` becomes undefined after the first iteration
[ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] . reduce ( ( acc , item , index ) => {
const flatten = acc . concat ( item ) ;
} ) ;
// good
[ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] . reduce ( ( acc , item , index ) => {
const flatten = acc . concat ( item ) ;
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 ;
} ) ;
4.8 Utilice saltos de línea después de abrir los corchetes de la matriz y antes de cerrarlos, si una matriz tiene varias líneas
// bad
const arr = [
[ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ,
] ;
const objectInArray = [ {
id : 1 ,
} , {
id : 2 ,
} ] ;
const numberInArray = [
1 , 2 ,
] ;
// good
const arr = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] ;
const objectInArray = [
{
id : 1 ,
} ,
{
id : 2 ,
} ,
] ;
const numberInArray = [
1 ,
2 ,
] ;
⬆ volver arriba
5.1 Utilice la desestructuración de objetos al acceder y utilizar múltiples propiedades de un objeto. eslint: prefer-destructuring
¿Por qué? La desestructuración le evita crear referencias temporales para esas propiedades y evitar el acceso repetitivo al objeto. El acceso repetido a objetos crea código más repetitivo, requiere más lectura y crea más oportunidades de cometer errores. La desestructuración de objetos también proporciona un sitio único de definición de la estructura del objeto que se usa en el bloque, en lugar de requerir la lectura de todo el bloque para determinar qué se usa.
// 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 Utilice la desestructuración de matrices. eslint: prefer-destructuring
const arr = [ 1 , 2 , 3 , 4 ] ;
// bad
const first = arr [ 0 ] ;
const second = arr [ 1 ] ;
// good
const [ first , second ] = arr ;
5.3 Utilice la desestructuración de objetos para múltiples valores de retorno, no la desestructuración de matrices.
¿Por qué? Puede agregar nuevas propiedades a lo largo del tiempo o cambiar el orden de las cosas sin interrumpir los sitios de llamadas.
// 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 , top } = processInput ( input ) ;
⬆ volver arriba
6.1 Utilice comillas simples ''
para cadenas. eslint: quotes
// bad
const name = "Capt. Janeway" ;
// bad - template literals should contain interpolation or newlines
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 mediante la concatenación de cadenas.
¿Por qué? Es doloroso trabajar con cadenas rotas y hacen que el código sea menos fácil de buscar.
// 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.3 Cuando cree cadenas mediante programación, utilice cadenas de plantilla en lugar de concatenación. eslint: prefer-template
template-curly-spacing
¿Por qué? Las cadenas de plantilla le brindan una sintaxis concisa y legible con nuevas líneas adecuadas y funciones de interpolación de cadenas.
// 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 } ?` ;
}
eval()
en una cadena; abre demasiadas vulnerabilidades. eslint: no-eval
6.5 No escape innecesariamente caracteres en cadenas. eslint: no-useless-escape
¿Por qué? Barras invertidas