? La guía completa ahora está disponible en Amazon

let , const y bloqueo let le permita crear declaraciones que estén vinculadas a cualquier bloque, llamado bloqueo de bloque. En lugar de usar var , que proporciona alcance de la función, se recomienda usar variables de alcance de bloque ( let o const ) en ES6.
var a = 2 ;
{
let a = 3 ;
console . log ( a ) ; // 3
let a = 5 ; // TypeError: Identifier 'a' has already been declared
}
console . log ( a ) ; // 2 Otra forma de declaración de bloqueo de bloques es el const , que crea constantes. En ES6, un const representa una referencia constante a un valor. En otras palabras, los contenidos de Object y Array pueden cambiar, solo se evita la reasignación de la variable. Aquí hay un ejemplo simple:
{
const b = 5 ;
b = 10 ; // TypeError: Assignment to constant variable
const arr = [ 5 , 6 ] ;
arr . push ( 7 ) ;
console . log ( arr ) ; // [5,6,7]
arr = 10 ; // TypeError: Assignment to constant variable
arr [ 0 ] = 3 ; // value is mutable
console . log ( arr ) ; // [3,6,7]
}Algunas cosas a tener en cuenta:
let y const varían del oso tradicional de variables y funciones. Tanto let y const son anchos, pero no se puede acceder antes de su declaración, debido a la zona muerta temporallet y const se alcanzan al bloque de encerrado más cercano.const PI = 3.14 )const tiene que definirse con su declaración.const let , a menos que planee reasignar la variable. Las funciones de flecha son una notación de mano corta para escribir funciones en ES6. La definición de la función de flecha consiste en una lista de parámetros ( ... ) , seguido de la marcador => y un cuerpo de funciones. Para las funciones de argumento único, se pueden omitir los paréntesis.
// Classical Function Expression
function addition ( a , b ) {
return a + b ;
} ;
// Implementation with arrow function
const addition = ( a , b ) => a + b ;
// With single argument, no parentheses required
const add5 = a => 5 + a ; Tenga en cuenta que en el ejemplo anterior, la función de flecha addition se implementa con "Concise Body" que no necesita una declaración de devolución explícita. NOTA el omitido { } después de la => .
Aquí hay un ejemplo con el "cuerpo de bloque" habitual. Incluyendo los envoltorios de aparato ortopédico rizado.
const arr = [ 'apple' , 'banana' , 'orange' ] ;
const breakfast = arr . map ( fruit => {
return fruit + 's' ;
} ) ;
console . log ( breakfast ) ; // ['apples', 'bananas', 'oranges']¡Mirad! Hay más ...
Las funciones de flecha no solo acortan el código. Están estrechamente relacionados con this comportamiento vinculante.
El comportamiento de las funciones de flecha con this palabra clave varía del de las funciones normales. Cada función en JavaScript define su propio this , pero las funciones de flecha capturan this valor del contexto encerrado más cercano. Consulte el siguiente código:
function Person ( ) {
// The Person() constructor defines `this` as an instance of itself.
this . age = 0 ;
setInterval ( function growUp ( ) {
// In non-strict mode, the growUp() function defines `this`
// as the global object, which is different from the `this`
// defined by the Person() constructor.
this . age ++ ;
} , 1000 ) ;
}
var p = new Person ( ) ; En ECMAScript 3/5, este problema se solucionó asignando el valor en this a una variable que podría cerrarse.
function Person ( ) {
const self = this ;
self . age = 0 ;
setInterval ( function growUp ( ) {
// The callback refers to the `self` variable of which
// the value is the expected object.
self . age ++ ;
} , 1000 ) ;
}Como se mencionó anteriormente, las funciones de Arrow capturan el valor del contexto de encerrado más cercano, por lo que el siguiente código funciona como se esperaba, incluso con funciones de flecha anidada.
function Person ( ) {
this . age = 0 ;
setInterval ( ( ) => {
setTimeout ( ( ) => {
this . age ++ ; // `this` properly refers to the person object
} , 1000 ) ;
} , 1000 ) ;
}
let p = new Person ( ) ;Lea más sobre 'léxico esto' en las funciones de flecha aquí
ES6 le permite establecer parámetros predeterminados en definiciones de funciones. Aquí hay una ilustración simple.
const getFinalPrice = ( price , tax = 0.7 ) => price + price * tax ;
getFinalPrice ( 500 ) ; // 850 ... El operador se conoce como operador de propagación o descanso, dependiendo de cómo y dónde se usa.
Cuando se usa con cualquier iterable, actúa para "extenderlo" en elementos individuales:
const makeToast = ( breadType , topping1 , topping2 ) => {
return `I had ${ breadType } toast with ${ topping1 } and ${ topping2 } ` ;
} ; const ingredients = [ 'wheat' , 'butter' , 'jam' ] ;
makeToast ( ... ingredients ) ;
// "I had wheat toast with butter and jam"
makeToast ( ... [ 'sourdough' , 'avocado' , 'kale' ] ) ;
// "I had sourdough toast with avocado and kale"La propagación también es excelente para dar forma a un nuevo objeto de otros objetos:
const defaults = { avatar : 'placeholder.jpg' , active : false }
const userData = { username : 'foo' , avatar : 'bar.jpg' }
console . log ( { created : '2017-12-31' , ... defaults , ... userData } )
// {created: "2017-12-31", avatar: "bar.jpg", active: false, username: "foo"}Las nuevas matrices también se pueden moldear expresivamente:
const arr1 = [ 1 , 2 , 3 ] ;
const arr2 = [ 7 , 8 , 9 ] ;
console . log ( [ ... arr1 , 4 , 5 , 6 , ... arr2 ] ) // [1, 2, 3, 4, 5, 6, 7, 8, 9] El otro uso común de ... es reunir todos los argumentos en una matriz. Esto se conoce como operador "REST".
function foo ( ... args ) {
console . log ( args ) ;
}
foo ( 1 , 2 , 3 , 4 , 5 ) ; // [1, 2, 3, 4, 5]ES6 permite declarar literales de objetos proporcionando sintaxis de taquigrafía para inicializar las propiedades de las variables y la definición de métodos de función. También permite la capacidad de tener claves de propiedad calculadas en una definición literal de objetos.
function getCar ( make , model , value ) {
return {
// with property value shorthand
// syntax, you can omit the property
// value if key matches variable
// name
make , // same as make: make
model , // same as model: model
value , // same as value: value
// computed values now work with
// object literals
[ 'make' + make ] : true ,
// Method definition shorthand syntax
// omits `function` keyword & colon
depreciate ( ) {
this . value -= 2500 ;
}
} ;
}
let car = getCar ( 'Kia' , 'Sorento' , 40000 ) ;
console . log ( car ) ;
// {
// make: 'Kia',
// model:'Sorento',
// value: 40000,
// makeKia: true,
// depreciate: function()
// } ES6 tiene un nuevo apoyo para los literales octales y binarios. Prepender un número con 0o o 0O lo convertiría en valor octal. Eche un vistazo al siguiente código:
let oValue = 0o10 ;
console . log ( oValue ) ; // 8
let bValue = 0b10 ; // 0b or 0B for binary
console . log ( bValue ) ; // 2La destrucción ayuda a evitar la necesidad de variables temporales cuando se trata de objetos y matrices.
function foo ( ) {
return [ 1 , 2 , 3 ] ;
}
let arr = foo ( ) ; // [1,2,3]
let [ a , b , c ] = foo ( ) ;
console . log ( a , b , c ) ; // 1 2 3 function getCar ( ) {
return {
make : 'Tesla' ,
model : 'g95' ,
metadata : {
vin : '123abc' ,
miles : '12000'
}
} ;
}
const { make , model } = getCar ( ) ;
console . log ( make , model ) ; // Tesla g95
const { make , metadata : { miles } } = getCar ( ) ;
console . log ( make , miles ) ; // Tesla 12000
ES6 permite usar super método en objetos (sin clase) con prototipos. El siguiente es un ejemplo simple:
const parent = {
foo ( ) {
console . log ( "Hello from the Parent" ) ;
}
}
const child = {
foo ( ) {
super . foo ( ) ;
console . log ( "Hello from the Child" ) ;
}
}
Object . setPrototypeOf ( child , parent ) ;
child . foo ( ) ; // Hello from the Parent
// Hello from the ChildES6 introduce una forma más fácil de agregar interpolaciones que se evalúan automáticamente.
`${ ... }` se usa para representar las variables.` Backtick se usa como delimitador. let user = 'Kevin' ;
console . log ( `Hi ${ user } !` ) ; // Hi Kevin!for...of iteraciones sobre objetos iterables, como la matriz. const nicknames = [ 'di' , 'boo' , 'punkeye' ] ;
nicknames . size = 3 ;
for ( let nickname of nicknames ) {
console . log ( nickname ) ;
}
// di
// boo
// punkeyefor...in iteraciones sobre todas las propiedades enumerables de un objeto. const nicknames = [ 'di' , 'boo' , 'punkeye' ] ;
nicknames . size = 3 ;
for ( let nickname in nicknames ) {
console . log ( nickname ) ;
}
// 0
// 1
// 2
// size ES6 introduce un nuevo conjunto de estructuras de datos llamadas Map y WeakMap . Ahora, en realidad usamos mapas en JavaScript todo el tiempo. De hecho, cada objeto puede considerarse como un Map .
Un objeto está hecho de claves (siempre cadenas) y valores, mientras que en Map , cualquier valor (tanto objetos como valores primitivos) puede usarse como una clave o un valor. Eche un vistazo a este código:
const myMap = new Map ( ) ;
const keyString = "a string" ,
keyObj = { } ,
keyFunc = ( ) => { } ;
// setting the values
myMap . set ( keyString , "value associated with 'a string'" ) ;
myMap . set ( keyObj , "value associated with keyObj" ) ;
myMap . set ( keyFunc , "value associated with keyFunc" ) ;
myMap . size ; // 3
// getting the values
myMap . get ( keyString ) ; // "value associated with 'a string'"
myMap . get ( keyObj ) ; // "value associated with keyObj"
myMap . get ( keyFunc ) ; // "value associated with keyFunc"Mapa débil
Un WeakMap es un mapa en el que las claves están débilmente referenciadas, que no evita que sus claves sean recolectadas de basura. Eso significa que no tiene que preocuparse por las filtraciones de memoria.
Otra cosa a tener en cuenta aquí, en WeakMap en lugar de Map cada clave debe ser un objeto .
Un WeakMap solo tiene cuatro métodos delete(key) , has(key) , get(key) y set(key, value) .
const w = new WeakMap ( ) ;
w . set ( 'a' , 'b' ) ;
// Uncaught TypeError: Invalid value used as weak map key
const o1 = { } ,
o2 = ( ) => { } ,
o3 = window ;
w . set ( o1 , 37 ) ;
w . set ( o2 , "azerty" ) ;
w . set ( o3 , undefined ) ;
w . get ( o3 ) ; // undefined, because that is the set value
w . has ( o1 ) ; // true
w . delete ( o1 ) ;
w . has ( o1 ) ; // falseLos objetos establecidos son colecciones de valores únicos. Se ignoran los valores duplicados, ya que la colección debe tener todos los valores únicos. Los valores pueden ser tipos primitivos u referencias de objetos.
const mySet = new Set ( [ 1 , 1 , 2 , 2 , 3 , 3 ] ) ;
mySet . size ; // 3
mySet . has ( 1 ) ; // true
mySet . add ( 'strings' ) ;
mySet . add ( { a : 1 , b : 2 } ) ; Puede iterar sobre un conjunto por orden de inserción utilizando el método forEach o el for...of bucle.
mySet . forEach ( ( item ) => {
console . log ( item ) ;
// 1
// 2
// 3
// 'strings'
// Object { a: 1, b: 2 }
} ) ;
for ( let value of mySet ) {
console . log ( value ) ;
// 1
// 2
// 3
// 'strings'
// Object { a: 1, b: 2 }
} Los conjuntos también tienen los métodos delete() y clear() .
Juego débil
Similar a WeakMap , el objeto WeakSet le permite almacenar objetos débilmente sostenidos en una colección. Un objeto en el WeakSet ocurre solo una vez; Es único en la colección del setset.
const ws = new WeakSet ( ) ;
const obj = { } ;
const foo = { } ;
ws . add ( window ) ;
ws . add ( obj ) ;
ws . has ( window ) ; // true
ws . has ( foo ) ; // false, foo has not been added to the set
ws . delete ( window ) ; // removes window from the set
ws . has ( window ) ; // false, window has been removedES6 presenta una nueva sintaxis de clase. Una cosa a tener en cuenta aquí es que la clase ES6 no es un nuevo modelo de herencia orientado a objetos. Simplemente sirven como un azúcar sintáctico sobre la herencia basada en prototipos existentes de JavaScript.
Una forma de ver una clase en ES6 es solo una nueva sintaxis para funcionar con prototipos y funciones de constructor que usaríamos en ES5.
Funciones definidas utilizando la palabra clave static Implementar funciones estáticas/de clase en la clase.
class Task {
constructor ( ) {
console . log ( "task instantiated!" ) ;
}
showId ( ) {
console . log ( 23 ) ;
}
static loadAll ( ) {
console . log ( "Loading all tasks.." ) ;
}
}
console . log ( typeof Task ) ; // function
const task = new Task ( ) ; // "task instantiated!"
task . showId ( ) ; // 23
Task . loadAll ( ) ; // "Loading all tasks.."extiende y super en clases
Considere el siguiente código:
class Car {
constructor ( ) {
console . log ( "Creating a new car" ) ;
}
}
class Porsche extends Car {
constructor ( ) {
super ( ) ;
console . log ( "Creating Porsche" ) ;
}
}
let c = new Porsche ( ) ;
// Creating a new car
// Creating Porsche extends permiten que la clase infantil herede de la clase principal en ES6. Es importante tener en cuenta que el constructor derivado debe llamar super() .
Además, puede llamar al método de la clase principal en los métodos de la clase infantil utilizando super.parentMethodName()
Lea más sobre las clases aquí
Algunas cosas a tener en cuenta:
function al definir funciones dentro de una definición de clase. Un Symbol es un tipo de datos único e inmutable introducido en ES6. El propósito de un símbolo es generar un identificador único, pero nunca puede obtener acceso a ese identificador.
Así es como creas un símbolo:
const sym = Symbol ( "some optional description" ) ;
console . log ( typeof sym ) ; // symbol Tenga en cuenta que no puede usar new con Symbol(…) .
Si se usa un símbolo como propiedad/clave de un objeto, se almacena de manera especial que la propiedad no aparezca en una enumeración normal de las propiedades del objeto.
const o = {
val : 10 ,
[ Symbol ( "random" ) ] : "I'm a symbol" ,
} ;
console . log ( Object . getOwnPropertyNames ( o ) ) ; // val Para recuperar las propiedades del símbolo de un objeto, use Object.getOwnPropertySymbols(o)
Un iterador accede a los elementos desde una colección uno a la vez, mientras realiza un seguimiento de su posición actual dentro de esa secuencia. Proporciona un método next() que devuelve el siguiente elemento en la secuencia. Este método devuelve un objeto con dos propiedades: Listo y valor.
ES6 tiene Symbol.iterator que especifica el iterador predeterminado para un objeto. Cada vez que se necesita iterarse un objeto (como al comienzo de A For ... de bucle), su método iterador @@ se llama sin argumentos, y el iterador devuelto se usa para obtener los valores que se iteran.
Veamos una matriz, que es iterable, y el iterador que puede producir para consumir sus valores:
const arr = [ 11 , 12 , 13 ] ;
const itr = arr [ Symbol . iterator ] ( ) ;
itr . next ( ) ; // { value: 11, done: false }
itr . next ( ) ; // { value: 12, done: false }
itr . next ( ) ; // { value: 13, done: false }
itr . next ( ) ; // { value: undefined, done: true } Tenga en cuenta que puede escribir iteradores personalizados definiendo obj[Symbol.iterator]() con la definición de objeto.
Las funciones del generador son una nueva característica en ES6 que permite que una función genere muchos valores a lo largo del tiempo devolviendo un objeto que se puede iterar para extraer los valores de la función un valor a la vez.
Una función del generador devuelve un objeto iterable cuando se llama. Se escribe utilizando la nueva * sintaxis, así como la nueva palabra clave de yield introducida en ES6.
function * infiniteNumbers ( ) {
let n = 1 ;
while ( true ) {
yield n ++ ;
}
}
const numbers = infiniteNumbers ( ) ; // returns an iterable object
numbers . next ( ) ; // { value: 1, done: false }
numbers . next ( ) ; // { value: 2, done: false }
numbers . next ( ) ; // { value: 3, done: false }Cada vez que se llama rendimiento , el valor producido se convierte en el siguiente valor en la secuencia.
Además, tenga en cuenta que los generadores calculan sus valores arrojados a pedido, lo que les permite representar eficientemente secuencias que son caras de calcular, o incluso secuencias infinitas.
ES6 tiene apoyo nativo para las promesas. Una promesa es un objeto que está esperando que se complete una operación asincrónica, y cuando se completa esa operación, la promesa se cumple (resuelta) o se rechaza.
La forma estándar de crear una promesa es usar el new Promise() que acepta un controlador que recibe dos funciones como parámetros. El primer manejador (generalmente llamado resolve ) es una función para llamar con el valor futuro cuando está listo; Y el segundo manejador (típicamente nombrado reject ) es una función para llamar para rechazar la promesa si no puede resolver el valor futuro.
const p = new Promise ( ( resolve , reject ) => {
if ( /* condition */ ) {
resolve ( /* value */ ) ; // fulfilled successfully
} else {
reject ( /* reason */ ) ; // error, rejected
}
} ) ; Cada promesa tiene un método nombrado then que toma un par de devoluciones de llamada. La primera devolución de llamada se llama si la promesa se resuelve, mientras que la segunda se llama si la promesa se rechaza.
p . then ( ( val ) => console . log ( "Promise Resolved" , val ) ,
( err ) => console . log ( "Promise Rejected" , err ) ) ; Devolver un valor a partir de then las devoluciones de llamada pasarán el valor al siguiente then la devolución de llamada.
const hello = new Promise ( ( resolve , reject ) => { resolve ( "Hello" ) } ) ;
hello . then ( ( str ) => ` ${ str } World` )
. then ( ( str ) => ` ${ str } !` )
. then ( ( str ) => console . log ( str ) ) // Hello World!Al devolver una promesa, el valor resuelto de la promesa se pasará a la próxima devolución de llamada para encadenarlos de manera efectiva. Esta es una técnica simple para evitar el "infierno de devolución de llamada".
const p = new Promise ( ( resolve , reject ) => { resolve ( 1 ) } ) ;
const eventuallyAdd1 = ( val ) => new Promise ( ( resolve , reject ) => { resolve ( val + 1 ) } ) ;
p . then ( eventuallyAdd1 )
. then ( eventuallyAdd1 )
. then ( ( val ) => console . log ( val ) ) ; // 3