- Inicio
- Árbol de directorios
- Jade
- Stylus
- JS
- Tipos
- Variables
- Objetos
- Propiedades
- Arrays
- Destructuring
- Strings
- Functions
- Constructores
- Modulos
- Iteradores y constructores
- Hoisting
- Operadores de comparación e igualdad
- Bloques
- Comentarios
- Espacios
- Comas
- Punto y coma
- Type Casting & Coercion
- Naming Conventions
- Accessors
- Eventos
- jQuery
- Rendimiento
- Recursos
- Guías de estilos
- http://devguides.clock.co.uk/
- http://google-styleguide.googlecode.com
- https://github.com/airbnb/javascript/blob/master/README.md
- Gulp
- Automatizador de tareas
- BabelJs
- Compila JS con sintaxis EcmaScript6 a EcmaScript5
- Gulp-jade
- Compila Jade a HTML
- Gulp-Stylus
- Compila Stylus a CSS
- Express 4
- Servidor en NodeJs
- Mongodb
- Base de datos no relacional
node.js 4.0 o superior
git
por consola en la carpeta de nuestro proyecto escribir los siguientes comandos para instalar las dependencias:
- npm install
- gulp analize
- Hace la tarea run y analiza la complejidad del código js con plato
- gulp dist
- Minifica el proyecto dev a _public-dist y lo lanzaç
- gulp run
- Compila el proyecto dev a _deploy y lo lanza
- gulp test
- Hace la tarea run y lanza los test unitarios
- Usa el mismo nombre para todos los archivos del mismo tipo, que dependa la carpeta su identificación:
¿Por qué? Ya van a estar en carpetas diferentes sólo háríamos redundancia, de esta forma enseguida se sabe que son los archivos que contiene la carpeta, ides como sublime text te permiten buscar por carpeta y fichero.
// MAL
app/
app.module.js
app.config.js
app.routes.js
components/
calendar.directive.js
calendar.directive.html
user-profile.directive.js
user-profile.directive.html
layout/
shell.html
shell.controller.js
topnav.html
topnav.controller.js
people/
attendees.html
attendees.controller.js
speakers.html
speakers.controller.js
speaker-detail.html
speaker-detail.controller.js
services/
data.service.js
localstorage.service.js
logger.service.js
spinner.service.js
sessions/
sessions.html
sessions.controller.js
session-detail.html
session-detail.controller.js
// MAL
app/
app.module.js
app.config.js
app.routes.js
controllers/
attendees.js
session-detail.js
sessions.js
shell.js
speakers.js
speaker-detail.js
topnav.js
directives/
calendar.directive.js
calendar.directive.html
user-profile.directive.js
user-profile.directive.html
services/
dataservice.j
localstorage.js
logger.js
spinner.js
views/
attendees.html
session-detail.html
sessions.html
shell.html
speakers.html
speaker-detail.html
topnav.html
// BIEN
app/
config.js
module.js
routes.js
components/
calendar/
directive.js
main.jade
user-profile/
directive.js
main.jade
layout/
shell/
ctrl.js
main.jade
topnav/
main.jade
ctrl.js
people/
attendees/
ctrl.js
main.jade
speakers/
ctrl.js
main.jade
speaker-detail/
ctrlr.js
main.jade
services/
data.js
localstorage.js
logger.js
spinner.js
sessions/
sessions/
ctrl.js
main.jade
session-detail/
ctrl.js
main.jade- 4 Espacios de tabulación, tabulación como espacios no con la tecla TAB
¿Por qué? Ayuda a que el código se vea más claro, normalmente los monitores son panorámicos y sobra mucho espacio y si se escribe código limpio y claro no deberíamos tener mucho anidamiento, por lo que es más fácil de seguir un código tabulado en 4 que en 2
// MAL
function() {
∙∙const name
}
// BIEN
function() {
∙∙∙∙const name
}-
Comillas simples
¿Por qué? Son más claras y se escriben antes
-
Comentarios en mayúsculas
¿Por qué? Ayuda a indentificarlos y separarlos visualmente del resto del código
// MAL
let persona = {
nombre: "Edu"
}
// BIEN
let persona = {
nombre: 'Edu'
}-
Elemento con varios atributos: Si son varios se escribe un atributo en cada línea, incluye atributo en la línea de la etiqueta y paretesís de cierre en el último atributo. Sin , de separación y ordenados alfabéticamente.
¿Por qué? Ayuda a localizar de un vistazo los atributos, no poner ',' lo hace más fiel a la sintaxis html y fácil de ordenar para evitar tener repetidos
-
div omitido si hay class.
¿Por qué? No aporta nada ponerlos
-
Usar la sintaxis . para class en vez de escribirlo como atributo.
¿Por qué? Es más fiel a la sintaxis de css y ayuda a diferenciarse de los atributos
-
Escribir el texto seguido a la etiqueta.
¿Por qué? Es más natural y fácil de seguir que ponerlo en nueva línea con |
-
Escribir los comentarios como //-.
¿Por qué? Al compilar no estarán en el html
-
Clases antes de los atributos.
¿Por qué? Hace más fácil la lectura al ser localizada la clase fácilmente
//-MAL
div.container
div(class='lolo')
input(class='myInput' type='text' value='valor' ng-model='lala')
header(class='main-header')
a(href='/')
| Project Title
//-BIEN
.container
.lolo
input.myInput(ng-model='lala'
type='text'
value='valor')
header.main-header
a(href='/') Project Title- Las variables se pondrán con el igual cuando estén solas y con #{variable} cuando estén junto con texto.
¿Por qué? Porque es más natural no ponerlas entre '' pero es mejor ponerlas entre '' a concatenarlas para la lectura
//-MAL
h1 #{title}
a(href='#{link}')
h1 Welcome to #{title}.
//-BIEN
h1=title
a(href=link)
h1 Welcome to #{title}.-
Seguir la guía de js cuando aplique para jade (var, if, mixins).
¿Por qué? Ayuda a legibilidad seguir estandarización del código
-
No usar - delante de sentencias de condicionales(if, case, each).
¿Por qué? Es más fiel a la sintaxis de JS y nos quitamos carácteres innecesarios
//-MAL
- each i in [1,2,3]
- if (foo == bar)
+baz(a,b,c)
//-BIEN
each i in [1, 2, 3]
if foo === bar
+baz(a, b, c)- No tener jade duplicado.
¿Por qué? Hace el código más mantenible y legible
//-MAL
if (selected)
option(value=value, selected='selected')= name
else
option(value=value)= name
//-BIEN
option(selected=selected
value=value)= name- Espacio vertical cada vez que acabamos un anidamiento.
¿Por qué? Hace el código más legible
//-MAL
div a
div b
div b-1
div b-2
div b-3
div c
div c-1
div c-2-1
div c-2-2
div c-2
div d
//-BIEN
div a
div b
div b-1
div b-2
div b-3
div c
div c-1
div c-2-1
div c-2-2
div c-2
div d-
Seguir la nomenclatura de Stylus.
¿Por qué? Es clara y limpia enfocándose más en el código
-
Línea en blanco de separación entre grupos de propiedades.
¿Por qué? Hace más fácil su seguimiento
-
Propiedades ordenadas alfabéticamente siempre que no afecte al resultado.
¿Por qué? Ayuda a localizar fácilmente las propiedades así como a o repetirlas
-
Usa nombres de clases identificativos y separados con -.
¿Por qué? Ayuda a claridad y sigue la misma nomenclatura que los atributos de html
-
Usa clases en vez de ids.
¿Por qué? Las clases pueden ser reutilizables
// MAL
.class1, .class2 {
position: relative;
color: blue;
}
.class1:hover, .class2:hover {
color: red;
}
// BIEN
.paragraph-left
.paragraph-right
color blue
position relative
&:hover
color red-
Espacios para separar -> = : { ( && || > = < y siguiente atributo.
¿Por qué? Hace más fácil su identificación a la hora d edesarrollar, mientras que para el despliegue del proyecto ya usaremos tareas de minificación.
-
No usar ;.
¿Por qué? Al usar babeljs ya nos los pondrá en el resultado final, mientras que a la hora de desarrollar esto permitirá que nuestro código sea más legible.
-
Usa const o let en lugar de var
¿Por qué? Ambas declaraciones no son hoisting como var, ayudando a seguir el orden lógico del código, su ámbito es a nivel de bloque y no de función, const evita que puedas cambiar el valor de una variable ayudando a evitar situaciones indesperadas.
-
Define en mayúsculas los nombres de las variables primitivas que se declaran con const, todas las demás con camelcase.
¿Por qué? Esa una buena práctica para identificarlas, mientras que para objetos y para funciones esto permitirá que no los sobreescribamos por error.
-
Si una función tiene sólo un return, y no es un objeto lo que devuelve, se escribe en una línea usando arrow y omitiendo las llaves y el return
¿Por qué? Una vez te acostumbras se ve más claro y mantenible
// MAL
var nombre = 'Edu'
saludar(nombre)
function saludar (nombre) {
return 'Hola ' + nombre
}
// BIEN
const NOMBRE = 'Edu'
const saludar = (nombre) => 'Hola ' + nombre
saludar(NOMBRE)-
Declaración de variables una por línea precedida de const o let.
¿Por qué? Facilita su ordenación y mantenimiento si hay que borrar o añadir alguna variable, ayuda a no confundirse con objetos cuando tenemos muchas declaraciones.
-
Ordenamiento alfabético siempre que sea posible tanto para variables como para propiedades.
¿Por qué? Facilita ver si algo está repetido, ayuda a que todo el código del sitio tenga el mismo orden facilitando su comprensión y lectura.
// MAL
const nombre = 'Edu',
apellido = 'Pérez',
edad = 31,
lugar = {
pais: 'España',
ciudad: 'Madrid',
comunidad: 'Madrid'
},
cara = {
ojos: 'marrones',
pelo: 'negro'
}
console.log(lugar.pais)
// BIEN
const APELLIDO = 'Pérez'
const EDAD = 31
const NOMBRE = 'Edu'
const cara = {
ojos: 'marrones',
pelo: 'negro'
}
const lugar = {
ciudad: 'Madrid',
comunidad: 'Madrid',
pais: 'España'
}
console.log(lugar.pais)-
Todas las funciones se declararán con
consty como expresión de función.¿Por qué? Hace que las declaraciones sigan el orden lógico al no ser hoisting y que no puedan ser sobreescritas por error
-
Todas las expresiones de función serán con la sintaxis => en vez de function excepto cuando queramos una nueva referencia a this
¿Por qué? Es más compacta y fácil su lectura y ayuda a dar un seguimiento real a this, lo cual es especialmente útil para los controladores de angularjs.
-
Línea en blanco de separación para separar grupos, condicionales, funciones.
¿Por qué? Facilita su localización y lectura
-
Para métodos encadenados ponlos en nueva línea empezando por . y sin tabulación extra, sí es sólo un método escribirlo en la misma línea.
¿Por qué? Ayuda para que no se ve aun salto con de taulación con el siguiente bloque, especialmente útil si hay una función en el método para que las llaves de cierre no queden con un salto, haciendo mejor su seguimiento.
// MAL
init()
function init() {
getData.get((data) => {
//CODE
})
.then(() => {
//CODE
})
return 'inicio'
}
// BIEN
const init = () => {
getData
.get((data) => {
//CODE
})
.then(() => {
//CODE
})
return 'inicio'
}
// MAL
$('#items').find('.selected').highlight().end().find('.open').updateCount()
// MAL
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount()
// BIEN
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount()
// MAL
$('#items')
.find('.selected')
// BIEN
$('#items').find('.selected')
// MAL
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
.call(tron.led)
// BIEN
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)init()
- Declarar las variables y propiedades de un objeto sólo cuando y donde son necesarias, no declararlas todas arriba y luego asignarlas.
> ¿Por qué? let y const no son hoisting, evita que una variable pueda ser declarada y no se use nunca, da un mejor seguimiento si queremos cambiar de nombre la variable o eliminarla, si el código está limpio sólo estamos añadiendo líneas de código innecesarias.
```javascript
// MAL
let apellido
let edad
let nombre
let lugar = {
ciudad: '',
comunidad: ''
pais: '',
}
const cara = {
ojos: '',
pelo: ''
}
const asignar = (value) => value
apellido = asignar('Pérez')
edad = asignar(31)
nombre = asignar('Edu')
$.get((data) => {
lugar = data.lugar
cara.ojos = data.cara.ojos
cara.pelo = data.cara.pelo
})
// BIEN
const asignar = (value) => value
const APELLIDO = asignar('Pérez')
const EDAD = asignar(31)
const NOMBRE = asignar('Edu')
let lugar
const cara = {}
$.get((data) => {
lugar = data.lugar
cara.ojos = data.cara.ojos
cara.pelo = data.cara.pelo
})
- Primitivos: Trabajas sobre su valor.
stringnumberbooleannullundefined
const FOO = 1
let bar = FOO
bar = 9
console.log(FOO, bar) // => 1, 9-
Complejos: Trabajas sobre su referencia.
objectarrayfunction
const foo = [1, 2]
const bar = foo
bar[0] = 9
console.log(foo[0], bar[0]) // => 9, 9- Usa
constpara las variables, objetos y funciones que no se tengan que volver a asignar, usaleten los demás casos, nunca usesvar. - Las variables primitivas declaradas con
constestarán en mayúsculas.
¿Por qué? Esto permite que no puedas cambiar el valor de la variable y que tengan
scopede bloque, en lugar descopedefunctioncomovar.
```javascript
// MAL
var a = 1
var b = 2
// BIEN
const A = 1
const B = 2
// MAL
var count = 1
if (true) {
count += 1
}
// BIEN
let count = 1
if (true) {
count += 1
}
// const y let sólo existen en los bloques que se definieron.
{
let a = 1
const B = 1
}
console.log(a) // ReferenceError
console.log(b) // ReferenceError
```
-
Siempre usa variables declaradas. No hacerlo hará que uses variables globales. Queremos evitar contaminar el
namespaceglobal.// MAL superPower = new SuperPower() // BIEN const superPower = new SuperPower()
-
Usa una declaración por variable.
¿Por qué? Es más fácil añadir nuevas variables de esta forma y ordenarlas. Evitas declarar una variable global por error.
// muy mal const DRAGONBALL = 'z', GOSPORTSTEAM = true ITEMS = getItems() // MAL const DRAGONBALL = 'z', GOSPORTSTEAM = true, items = getItems() // BIEN const DRAGONBALL = 'z' const GOSPORTSTEAM = true const ITEMS = getItems()
-
Agrupa todos tus
consts y luego agrupa todos tuslets.
¿Por qué? Ayuda a identificar mejor las variables.
```javascript
// MAL
let i, len, dragonball,
items = getItems(),
goSportsTeam = true
// MAL
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
```
- Asigna variables cuando las necesites pero en un lugar razonable.
¿Por qué? El alcance de
letyconstes a nivel de bloque y no de función.
```javascript
// BIEN
function() {
test()
console.log('doing stuff..')
//..other stuff..
const name = getName()
if (name === 'test') {
return false
}
return name
}
// MAL - llamada innecesaria a función
function(hasName) {
const name = getName()
if (!hasName) {
return false
}
this.setFirstName(name)
return true
}
// BIEN
function(hasName) {
if (!hasName) {
return false
}
const name = getName()
this.setFirstName(name)
return true
}
```
- Usa la sintaxis literal para crearlo.
// mal
const item = new Object()
// bien
const item = {}- Usa
computed property namescuando crees objetos con propiedades dinámicas.
const getKey = (k) => `a key named ${k}`
// mal
const obj = {
id: 5,
name: 'San Francisco'
}
obj[getKey('enabled')] = true
// bien
const obj = {
[getKey('enabled')]: true,
id: 5,
name: 'San Francisco'
}- Usa el método abreviado para definir métodos.
// mal
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value
}
}
// bien
const atom = {
value: 1,
addValue(value) {
return atom.value + value
}
}-
Usa el método abreviado para definir propiedades.
¿Por qué? Evitas redundancia.
const lukeSkywalker = 'Luke Skywalker'
// mal
const obj = {
lukeSkywalker: lukeSkywalker
}
// bien
const obj = {
lukeSkywalker
}-
Agrupa las propiedades por grupos y alfabéticamente.
¿Por qué? Hará más fácil su identificación.
const anakinSkywalker = 'Anakin Skywalker'
const lukeSkywalker = 'Luke Skywalker'
// mal
const obj = {
episodeOne: 1,
twoJedisWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
}
// bien
const obj = {
anakinSkywalker,
lukeSkywalker,
episodeOne: 1,
episodeThree: 3,
mayTheFourth: 4,
twoJedisWalkIntoACantina: 2
}- Utilice la notación de puntos cuando acceda a las propiedades.
const luke = {
age: 28,
jedi: true
}
// MAL
const isJedi = luke['jedi']
// BIEN
const isJedi = luke.jedi- Us la notación
[]cuando accedas a una propiedad con una variable.
const luke = {
age: 28,
jedi: true
}
const getProp = (prop) => luke[prop]
const isJedi = getProp('jedi')- Usa la sintaxis literal para crearlo.
// mal
const items = new Array()
// bien
const items = []- usa array.push en lugar de asignar una posición nueva del Array.
const someStack = []
// mal
someStack[someStack.length] = 'abracadabra'
// bien
someStack.push('abracadabra')- Usa
...para copiar arrays.
// mal
const itemsCopy = []
const LEN = items.length
for (let i = 0; i < LEN; i++) {
itemsCopy.push(items[i])
}
// bien
const itemsCopy = [...items]- Para convertir un objeto en un
Arrayusararray.from.
const foo = document.querySelectorAll('.foo')
const nodes = Array.from(foo)- Úsalo para acceder y usar múltiples propiedades de un objeto.
// mal
const getFullName = (user) => {
const FIRSTNAME = user.firstName
const LASTNAME = user.lastName
return `${FIRSTNAME} ${LASTNAME}`
}
// bien
const getFullName = (obj) => {
const {firstName, lastName} = obj
return `${firstName} ${lastName}`
}
// mejor
const getFullName = ({ firstName, lastName }) => `${firstName} ${lastName}`- Uso en Arrays.
const arr = [1, 2, 3, 4]
// mal
const first = arr[0]
const second = arr[1]
// bien
const [first, second] = arr-
Para múltiples valores devueltos, usa
Destructuring de objetos, no de arrays.¿Por qué? Puedes añadir nuevas propiedades o cambiar el orden sin alterar otras llamadas.
// mal
function processInput(input) {
return [
left,
right,
top,
bottom
]
}
// la llamada necesita pensar sobre el orden establecido
const [left, __, top] = processInput(input)
// bien
const processInput = (input) => {
return {
bottom
left,
right,
top
}
}
// la llamada sólo selecciona los datos que necesita
const {left, right} = processInput(input)- Usa comillas simples
''.
// mal
const name = "Capt. Janeway"
// bien
const name = 'Capt. Janeway'- Usa multilínea con `` y ponlo en nueva línea con una tabulación.
// mal
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.'
// mal
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.'
// mal
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.'
// bien
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.`- Usa plantillas de cadenas
template Stringsen lugar de concatenación.¿Por qué?. Da claridad a la lectura y permite multilínea
// mal
const sayHi = (name) => 'How are you, ' + name + '?'
// mal
const sayHi = (name) => ['How are you, ', name, '?'].join()
// bien
const sayHi = (name) => `How are you, ${name}?`- Usa
function expressionssiempre conconsty la sintaxisfunction arrow - Usa siempre
function expressionsen lugar defunction declarations. - No uses
function arrowexcepto que quieras quethisno acceda al antecesorfunctionmás cercano sino a su propio ámbito.
¿Por qué?. Permite ver claramente el ámbito de
this, permitescopepor bloque, nos aseguramos de escribir el código secuencialmente para una mejor lectura, cuando usemosfunction arrowpermite la sintaxis corta de una línea.
// MAL
(function () {
console.log('Welcome to the Internet. Please follow me.')
})()
// BIEN
(() => {
console.log('Welcome to the Internet. Please follow me.')
})()
// MAL
function foo() {
}
// BIEN
const foo = function () {
}
// MAL
[1, 2, 3].map(function (x) {
return x * x
})
// BIEN
[1, 2, 3].map((x) => {
return x * x
})
//MEJOR
[1, 2, 3].map((x) => x * x)- Si el cuerpo de una función es sólo una línea, es preferible usar la sintaxys última.
¿Por qué? Es más fácil de leer.
¿Cuándo no? Si quieres devolver un objeto.
// BIEN
[1, 2, 3].map((x) => {
return {number: x}
})- Usa siempre paréntesis en los argumentos aunque para uno no haga falta
¿Por qué? Se leen mejor con paréntesis. Son requeridos cuando tienes varios parámetros.
// MAL
[1, 2, 3].map(x => x * x)
// BIEN
[1, 2, 3].map((x) => x * x)- Nunca declarar una función dentro de un condicional. En su lugar asigna la función a una variable. Los navegadores lo permiten pero lo tratan diferente.
// MAL
if (currentUser) {
function test() {
console.log('Nope.')
}
}
// BIEN
let test
if (currentUser) {
test = () => {
console.log('Yup.')
}
}- Nunca llames a ur argumento
arguments.
// MAL
const nope = (name, options, arguments) => {
}
// BIEN
const yup = (name, options, args) => {
}- Nunca usar
arguments, usar....
¿Por qué?
...es un Array yargumentssimula ser un Array.
// MAL
const concatenateAll = () => {
const args = Array.prototype.slice.call(arguments)
return args.join('')
}
// BIEN
const concatenateAll = (...args) => args.join('')- Usa la sintaxis de parámetros por defecto en lugar de
||, ya que esto puede hacer que cambie el tipo.
// MAL
const handleThings = (opts) => opts = opts || {}
// MAL
const handleThings = (opts) => {
if (opts === void 0) {
opts = {}
}
}
// BIEN
const handleThings = (opts = {}) => {
}- Evitar efectos secundarios con los parámetros por defecto.
¿Por qué? Pueden confundir.
// MAL
let b = 1
const count = (a = b++) => console.log(a)
count() // 1
count() // 2
count(3) // 3
count() // 3- Siempre usa
class. En lugar deprototype.
¿Por qué? Sintaxis
classes más fácil de entender.
// MAL
const Queue = function (contents = []) {
this._queue = [...contents]
}
Queue.prototype.pop = function () {
const value = this._queue[0]
this._queue.splice(0, 1)
return value
}
// BIEN
class Queue {
constructor(contents = []) {
this._queue = [...contents]
}
pop() {
const value = this._queue[0]
this._queue.splice(0, 1)
return value
}
}- Usa
extendspara herencia.
¿Por qué? Es una manera de heredar el prototipo sin perder
instanceof.
// MAL
const inherits = require('inherits')
const PeekableQueue = function(contents) {
Queue.apply(this, contents)
}
inherits(PeekableQueue, Queue)
PeekableQueue.prototype.peek = function() {
return this._queue[0]
}
// BIEN
class PeekableQueue extends Queue {
peek() {
return this._queue[0]
}
}- Métodos pueden devolver
thispara ayudar a encadenar.
// MAL
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
// BIEN
class Jedi {
jump() {
this.jumping = true
return this
}
setHeight(height) {
this.height = height
return this
}
}
const luke = new Jedi()
luke
.jump()
.setHeight(20)- Está permitido escribir un método toString() customizado, sólo aseguraté de que eso no causa efectos inesperados.
class Jedi {
contructor(options = {}) {
this.name = options.name || 'no name'
}
getName() {
return this.name
}
toString() {
return `Jedi - ${this.getName()}`
}
}- Siempre usa módulos (
import/export) en lugar de los no estándar sistemas de módulos.
¿Por qué? Modules son el futuro, vamos a usar el futuro hoy.
// MAL
const AirbnbStyleGuide = require('./AirbnbStyleGuide')
module.exports = AirbnbStyleGuide.es6
// BIEN
import AirbnbStyleGuide from './AirbnbStyleGuide'
export default AirbnbStyleGuide.es6
//MEJOR
import { es6 } from './AirbnbStyleGuide'
export default es6- No uses
import *
¿Por qué? Esto hace que tengas una sola exportación por defecto.
// MAL
import * as AirbnbStyleGuide from './AirbnbStyleGuide'
// BIEN
import AirbnbStyleGuide from './AirbnbStyleGuide'- Y no exportar directamente de un
import.
¿Por qué? Aunque una línea es conciso, tener una forma más clara facilita la lectura.
// MAL
// filename es6.js
export { es6 as default } from './airbnbStyleGuide'
// BIEN
// filename es6.js
import { es6 } from './AirbnbStyleGuide'
export default es6- No usar iteradores. Mejor usar funciones tipo
map()yreduce()en lugar de buclesfor-of.
¿Por qué? Esto refuerza nuestra regla inmutable. Tratar con funciones puras que devuelven valores hace más fácil de evitar efetos secundarios.
const numbers = [1, 2, 3, 4, 5]
// MAL
let sum = 0
for (let num of numbers) {
sum += num
}
sum === 15
// BIEN
let sum = 0
numbers.forEach((num) => sum += num)
sum === 15
//MEJOR
const sum = numbers.reduce((total, num) => total + num, 0)
sum === 15- No usar generadores por ahora.
¿Por qué? No se pasan bien a ES5.
- Declaraciones de variables con
varson asignadas al top de la función, su asignamiento no. Las declaracionesconstylettienen un nuevo concepto. Es importante saber porque typeof ya no es seguro.
const example = () => console.log(notDefined) // => throws a ReferenceError
const example = () => {
console.log(declaredButNotAssigned) // => undefined
var declaredButNotAssigned = true
}
const example = () => {
console.log(declaredButNotAssigned) // => throws a ReferenceError
console.log(typeof declaredButNotAssigned) // => throws a ReferenceError
const declaredButNotAssigned = true
}- Una expresión de función anónima pone en el top su nombre de variable pero no el asignamiento.
function example() {
console.log(anonymous) // => undefined
anonymous() // => TypeError anonymous is not a function
var anonymous = function() {
console.log('anonymous function expression')
}
}- Una
function expresiondeclarada convarpone en el top su nombre de variable pero no el contenido de la función o su nombre.
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')
}
}
function example() {
console.log(named) // => undefined
named() // => TypeError named is not a function
var named = function named() {
console.log('named')
}
}- Funciones declaradas ponen en el top su nombre y asignamiento.
function example() {
superPower() // => Flying
function superPower() {
console.log('Flying')
}
}- Para más información JavaScript Scoping & Hoisting por Ben Cherry.
-
Usa
===y!==en lugar de==y!=. -
Operadores de comparación devuelven el siguiente
boolean:- Objects evalua a true
- Undefined evalua a false
- Null evalua a false
- Booleans evalua a the value of the boolean
- Numbers evalua a false si +0, -0, or NaN, sino true
- Strings evalua a false si
'', sino true
if ([0]) {
// true
// An array is an object, objects evaluate to true
}- No uses abreviatura excepto que quieras evaluar juntos false, 0, '0', null undefined.
- ¿Por qué?. Las abreviaturas(
truthy,falsy) hacen que tengamos menos control de nuestro código y por tanto son propensas a errores.
// MAL
if (name) {
// ...stuff...
}
// BIEN
if (name !== '') {
// ...stuff...
}
// MAL
if (collection.length) {
// ...stuff...
}
// BIEN
if (collection.length > 0) {
// ...stuff...
}- Para más información Igualdad y JavaScript por Angus Croll.
- Usa llaves con todos los bloques.
- ¿Por qué?. Ayuda a claridad, evita errores por multilinea en el if y prepara este por si hay que ampliarlo.
// MAL
if (test)
return false
// MAL
if (test) return false
// BIEN
if (test) {
return false
}
// MAL
function () {return false}
// BIEN
function () {
return false
}
// mejor
function () => false- Si estás usando bloques multilínea con
ifyelse, ponelseen la misma líneaque se cierra la llave delif.
// MAL
if (test) {
thing1()
thing2()
}
else {
thing3()
}
// BIEN
if (test) {
thing1()
thing2()
} else {
thing3()
}- Si tienes un bloque
ifelsede una línea cada uno, usa el operador ternario si es necesario.
// MAL
let isOpen
if (open() === true) {
isOpen = true
} else {
isOpen = false
}
// BIEN
let isOpen = (open() === true) ? true : false
//MEJOR
let isOpen = (open() === true)- Usa
/* ... */para comentarios multilínea. Añádele una tabulación. - Si es necesario incluye una descripción, específica tipos y valores para todos los parámetros y retorna valores.
// MAL
/**
* make() devuelve un nuevo elemento
* basado en el nombre de etiqueta
*
* @param {String} etiqueta
* @return {Element} elemento
*/
const make = (tag) => {
// ...stuff...
return element
}
// BIEN
/*
make() devuelve un nuevo elemento
basado en el nombre de etiqueta
@param {String} etiqueta
@return {Element} elemento
*/
const make = (tag) => {
// ...stuff...
return element
}- Usa
//para comentarios de una línea. Ponlos antes y deja un espacio vertical.
// MAL
const active = true // IS CURRENT TAB
// BIEN
// IS CURRENT TAB
const active = true
// MAL
const getType = () => {
console.log('fetching type...')
// SET THE DEFAULT TYPE TO 'no type'
const type = this._type || 'no type'
return type
}
// BIEN
const getType = () => {
console.log('fetching type...')
// SET THE DEFAULT TYPE TO 'no type'
const type = this._type || 'no type'
return type
}-
Prefijando tus comentarios con
FIXMEoTODOayuda a otros desarrolladores a entender si ese punto necesita revisión, o sugiere una solución. Las diferencias sonFIXME -- necesita arreglar un bugoTODO -- necesita implementar. -
Usa
// FIXME:para anotar problemas.
class Calculator {
constructor() {
// FIXME: debería usar un global aquí
total = 0
}
}- Usa
// TODO:para anotar soluciones a problemas.
class Calculator {
constructor() {
// TODO: total debe ser configurable en las opciones del parámetro
this.total = 0
}
}- Deja un espacio antes de una llave.
// MAL
function test(){
console.log('test')
}
// BIEN
function test() {
console.log('test')
}
// MAL
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog'
});
// BIEN
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog'
})- Pon 1 espacio antes de abrir el paréntesis de los condicionales. No ponerlo en llamadas a funciones o en
function declarations.
// MAL
if(isJedi) {
fight ()
}
// BIEN
if (isJedi) {
fight()
}
// MAL
function fight () {
console.log ('Swooosh!')
}
// BIEN
function fight() {
console.log('Swooosh!')
}- Asignar valores con espacios.
// MAL
const x=y+5
// BIEN
const x = y + 5- No terminar ficheros con una línea en blanco.
- ¿Por qué?. El propio automatizador de tareas se encarga de que los ficheros puedan minificarse.
// MAL
(function(global) {
// ...
})(this)↵
// BIEN
(function(global) {
// ...
})(this)- Deja una línea en blanco antes y después de un condicional y funciones
// MAL
if (foo) {
return bar
}
return baz
// BIEN
if (foo) {
return bar
}
return baz
// MAL
const obj = {
foo() {
},
bar() {
}
}
return obj
// BIEN
const obj = {
bar() {
},
foo() {
}
}
return obj- Comas al final de línea
// MAL
const story = [
once
, upon
, aTime
]
// BIEN
const story = [
once,
upon,
aTime
]
// MAL
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
}
// BIEN
const hero = {
birthYear: 1815,
firstName: 'Ada',
lastName: 'Lovelace',
superPower: 'computers'
}- Coma al final de conjunto de propiedades de un objeto.
¿Por qué? Aunque usando compiladores como babel ya nos quita la , en el resultado final es preferible no ponerla ya que no aporta nada.
- Nota personal: Los compiladores deberían permitir no ponerlas, no el poder poner todas que sólo ensucia el código al igual que ya hacen las clases que no necesitan separar sus métodos con , ya que se entiende que son un bloque.
// MAL
const hero = {
firstName: 'Dana',
lastName: 'Scully',
}
const heroes = [
'Batman',
'Superman',
]
// BIEN
const hero = {
firstName: 'Dana',
lastName: 'Scully'
}
const heroes = [
'Batman',
'Superman'
]- No usarlos más que para el
for - ¿Por qué?. Porque usando una guía de estilos y un automatizador de tareas no vamos a tener necesidad de
;ya que para nuestra versión final estarán donde deben. Facilita la lectura al quitar elementos inservibles.
// MAL
(function() {
const name = 'Skywalker';
return name;
})()
// BIEN
(function() {
const name = 'Skywalker'
return name
})()- Strings:
const reviewScore = 9
// MAL
const totalScore = reviewScore + ''
// BIEN
const totalScore = String(reviewScore)- Usa
Numberpara números.
const inputValue = '4'
// MAL
const val = parseInt(inputValue, 10)
// MAL
const val = +inputValue
// MAL (en uso intensivo, mejor rendimiento)
const val = inputValue >> 0
// MAL
const val = parseInt(inputValue)
// BIEN
const val = Number(inputValue)- Sólo por razones de rendimiento en un uso intensivo de Number se usaría notación Bitshift for razones del rendimiento.
// BIEN
const val = inputValue >> 0- Nota: Hay soporte para números a 64bits pero la notación Bitshift es 32 bits.
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647- Booleans:
const age = 0
// MAL
const hasAge = new Boolean(age)
// BIEN
const hasAge = Boolean(age)
// BIEN
const hasAge = !!age- Evita nombres con una letra. Se descriptivo con los nombres.
// MAL
function q() {
// ...
}
// BIEN
function query() {
// ..
}- Usa camelcase cuando nombres objetos, funciones e instancias.
// MAL
const OBJEcttsssss = {}
const this_is_my_object = {}
function c() {}
// BIEN
const thisIsMyObject = {}
function thisIsMyFunction() {}- Use PascalCase para llamar a constructores o clases.
// MAL
function user(options) {
this.name = options.name
}
const bad = new user({
name: 'nope'
})
// BIEN
class User {
constructor(options) {
this.name = options.name
}
}
const good = new User({
name: 'yup'
})- Usa
_al empezar el nombre de una propiedad privada.
// MAL
this.__firstName__ = 'Panda'
this.firstName_ = 'Panda'
// BIEN
this._firstName = 'Panda'- No guardes referencia a
this. Usaarrow functionsobind.
// MAL
const foo = () => {
const self = this
return () => console.log(self)
}
// MAL
const foo = () => {
const that = this
return () => console.log(that)
}
// BIEN
function foo() {
return () => {
console.log(this)
}
}
// mejor
function foo() {
return () => console.log(this)
}- Si tu fichero exporta una sóla clase, este debe llamarse igual que la clase.
class CheckBox {
// ...
}
export default CheckBox
// En otro fichero
// MAL
import CheckBox from './checkBox'
// MAL
import CheckBox from './check_box'
// BIEN
import CheckBox from './CheckBox'- Usa camelCase cuando exportes una
function. Tu nombre de fichero debe ser idéntico al nombre de lafunction.
function makeStyleGuide() {
}
export default makeStyleGuide- Use
PascalCasecuando exportes unsingleton / function library / bare object.
const AirbnbStyleGuide = {
es6: {
}
}
export default AirbnbStyleGuideAccessor functionspara propiedades no son requeridas.- Si haces
accessor functionsusa getVal() y setVal('hello').
// MAL
dragon.age()
// BIEN
dragon.getAge()
// MAL
dragon.mal(25)
// BIEN
dragon.setAge(25)- Si la propiedad es un
boolean, usa isVal() o hasVal().
// MAL
if (!dragon.age()) {
return false
}
// BIEN
if (!dragon.hasAge()) {
return false
}- Está permitido hacer funciones
get()yset()siempre que se hagan bien.
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue'
this.set('lightsaber', lightsaber)
}
get(key) {
return this[key]
}
set(key, val) {
this[key] = val
}
}- Procura pasar objetos, para que si alguien más tiene que contribuir en un futuro pueda hacerlo fácilmente sin afectar a lo anterior:
// MAL
$(this).trigger('listingUpdated', listing.id)
$(this).on('listingUpdated', function (e, listingId) {
// do something with listingId
})
// BIEN
$(this).trigger('listingUpdated', {listingId: listing.id})
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingId
})- Prefija variables de objetos jQuery con
$.
// MAL
const sidebar = $('.sidebar')
// BIEN
const $sidebar = $('.sidebar')- Cachea objetos jQuery.
// MAL
function setSidebar() {
$('.sidebar').hide()
$('.sidebar').css({
'background-color': 'pink'
});
}
// BIEN
function setSidebar() {
const $sidebar = $('.sidebar')
$sidebar.hide()
$sidebar.css({
'background-color': 'pink'
})
}- Para peticiones al DOM en cascada usa
$('.sidebar ul')o padre > hijo$('.sidebar > ul'). jsPerf - Usa
findsi tienes en una variable el objeto jQuery.
// MAL
$('ul', '.sidebar').hide()
// MAL
$('.sidebar').find('ul')
.hide()
// BIEN
$('.sidebar ul').hide()
// BIEN
$('.sidebar > ul').hide()
// BIEN
$sidebar.find('ul')
.hide()- 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
Aprendiendo ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Lee esto
Herramientas
- Code Style Linters
Guías de estilos
- 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
Otras lecturas
- 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
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts