io.js – o famoso Node.js O io.js obteve esses recursos antes do Node.js seguindo agressivamente as versões mais recentes do mecanismo V8 JavaScript. Como um observador externo, tirei algumas horas para dar uma olhada e relatarei minhas descobertas aqui.
Instalação
As distribuições binárias do io.js estão disponíveis no site página iniciale o senhor pode fazer o download de um binário para Linux, Windows, Mac ou criá-lo a partir do código-fonte. No entanto, os instaladores binários sobrescreverão o arquivo node
e npm
em seu sistema se o senhor tiver o Node.js instalado. Portanto, recomendo usar o nvm para instalar o io.js de forma livre de conflitos. A instalação do nvm é muito fácil se o senhor não tiver feito isso antes. Se e quando o senhor tiver nvm, basta fazer
$ nvm install io.js ######################################################################## 100.0% WARNING: checksums are currently disabled for io.js Now using io.js v1.0.3
Verifique se funcionou:
$ iojs >
Voilà! Observe que node
tem como alias o nome iojs
, e npm
ainda é chamado de npm
.
Visão geral dos recursos do ES6
Embora alguns pessoas têm já foram usando ES6 por um tempo por meio de transpiladores, quando trabalho com código transpilado, parece que estou tendo que depurar simultaneamente duas versões do código – o senhor não sabe o que está fazendo? A depuração já é difícil o suficiente com apenas uma versão. Por esse motivo, ter suporte nativo o torna muito mais atraente para mim.
O página ES6 do io.js fornece informações sobre as alterações que foram feitas no suporte a ES6 no mecanismo. Eles eliminaram a função --harmony
que no Node 0.11+ era necessário incluir se o usuário quisesse usar qualquer recurso ES6. No io.js, o senhor os obtém imediatamente! A lista atual de recursos do ES6 ativados por padrão é a seguinte:
let
declaraçãoconst
declaraçãoMap
eSet
WeakMap
eWeakSet
- Geradores
- Literais binários e octais
- Promessas
- Alguns métodos adicionais de string
- Símbolos
- Strings de gabarito
Eles também adicionaram o --es_staging
que permitiria que o senhor obtivesse acesso a recursos que estão prontos, mas que ainda não foram bem testados. Para os recursos que estão sendo implementados, o senhor terá de obter acesso a cada recurso individualmente usando o sinalizador de harmonia correspondente a ele. O senhor pode obter a lista de sinalizadores de recursos de harmonia via:
$ iojs --v8-options|grep "harmony" --es_staging (enable all completed harmony features) --harmony (enable all completed harmony features) --harmony_shipping (enable all shipped harmony fetaures) --harmony_modules (enable "harmony modules (implies block scoping)" (in progress)) --harmony_arrays (enable "harmony array methods" (in progress)) --harmony_array_includes (enable "harmony Array.prototype.includes" (in progress)) --harmony_regexps (enable "harmony regular expression extensions" (in progress)) --harmony_arrow_functions (enable "harmony arrow functions" (in progress)) --harmony_proxies (enable "harmony proxies" (in progress)) --harmony_sloppy (enable "harmony features in sloppy mode" (in progress)) --harmony_unicode (enable "harmony unicode escapes" (in progress)) --harmony_tostring (enable "harmony toString") --harmony_numeric_literals (enable "harmony numeric literals") --harmony_strings (enable "harmony string methods") --harmony_scoping (enable "harmony block scoping") --harmony_classes (enable "harmony classes (implies block scoping & object literal extension)") --harmony_object_literals (enable "harmony object literal extensions") --harmony_templates (enable "harmony template literals")
Agora, vamos nos aprofundar nos recursos individuais.
let
e const
O let
e const
só estão disponíveis no modo estrito. Portanto, coloque "use strict"
na parte superior de cada arquivo JS em que o senhor deseja usá-las.
O let
é um substituto para a declaração var
que tem escopo lexical. Isso significa que, embora uma variável definida com var
é visível para a função na qual foi declarada, let
é visível apenas para o bloco de código no qual foi declarado. Em JavaScript, um bloco de código é uma declaração composta entre {
e }
que contém zero ou mais instruções. É comum usar blocos de código dentro de instruções if, loops for, loops while e como o corpo de uma definição de função. Porém, também é possível escrever um bloco de código autônomo.
Aqui está um exemplo de let
:
"use strict" if (player.partner){ let partner = player.partner // do stuff with partner here } console.log(parter) // this throws partner is not defined
Aqui está let
em um loop for:
"use strict" for (let i = 0; i < 10; i++){ console.log(i) } console.log(i) // this throws i is not defined
const
é como se o let
exceto pelo fato de que, uma vez declarada, a variável não pode ser reatribuída a outro valor.
"use strict" const ITERATIONS_TO_RUN = 10 ITERATIONS_TO_RUN = 12 // throws TypeError: Assignment to constant variable.
Mapa e conjunto
O ES6 introduziu o Map
e Set
estruturas de dados para sua conveniência. Agora o senhor deve estar se perguntando: por que precisamos de um mapa? O que há de errado em usar literais de objetos como mapas? Bem, já se argumentou que o um objeto não é um hash (ou um mapa). A versão resumida é que um objeto herda todos os Object.prototype
o que, na maioria dos casos, não é desejável se o senhor quiser usá-lo como um mapa.
Agora, aqui está um exemplo de uso do Map
:
> var m = new Map undefined > m.set('name', 'Bobby') {} > m.get('name') Bobby > m.size 1 > m.set('age', 5) {} > m.has('age') true > m.has('foobar') false > m.forEach(function(value, key){ console.log(key + ' maps to ' + value) }) name maps to Bobby age maps to 5 > m.get('hasOwnProperty') // avoids the `hasOwnProperty` trap undefined > m.clear() undefined > m.size 0
E aqui está o Set em ação:
> var s = new Set undefined > s.add(1) {} > s.size 1 > s.add(2) {} > s.size 2 > s.add(1) // adding a duplicate here {} > s.size // no change in size 2 > s.has(1) true > s.has(2) true > s.has(3) false > s.forEach(function(n){ console.log('Set has ' + n) }) Set has 1 Set has 2
WeakMap e WeakSet
WeakMap
e WeakSet
são novos tipos de dados que espelham o Map
e Set
mas, ao contrário de Map
e Set
– que podem ser implementados como polyfills – esses só podem ser implementados nativamente. A palavra “fraco” refere-se ao referências fracas. A referência fraca é uma referência de objeto que é ignorada pelo coletor de lixo. Se existirem apenas referências fracas – não mais referências fortes – apontando para o objeto em questão, esse objeto poderá ser destruído e sua memória será devolvida.
Vamos falar sobre WeakSet
primeiro, porque é mais fácil de explicar. A WeakSet
é um subconjunto de Set
‘s. No entanto, o senhor não pode armazenar valores primitivos nela:
> var ws = new WeakSet undefined > ws.add(1) TypeError: Invalid value used in weak set
Isso faz sentido porque os valores primitivos são armazenados por valor, não por referência, e não faria sentido sequer falar em referências fracas. Portanto, em vez disso, o senhor precisará colocar objetos nele:
> var bob = {name: 'Bob'} undefined > var jen = {name: 'Jen'} undefined > ws.add(bob) {} > ws.add(jen) {} > ws.has(bob) true > ws.has(jen) true > var jim = {name: 'Jim'} undefined > ws.has(jim) false > ws.delete(jen) true > ws.has(jen) false
WeakSet
não tem size
ou uma forma de iterar seus membros
> ws.size undefined > ws.forEach(function(item){ console.log('WeakSet has ' + item)}) TypeError: undefined is not a function > ws.forEach undefined
Isso ocorre justamente porque as referências são fracas e, como tal, os objetos podem ser destruídos sem aviso prévio, o que impossibilitaria o acesso a eles. Um possível uso do WeakSet
é armazenar um conjunto de elementos DOM relacionados sem se preocupar com vazamentos de memória quando os elementos são removidos do documento.
A WeakMap
é como se o Map
exceto pelo fato de que todas as suas chaves são referências fracas. Elas também não podem ser valores primitivos.
var wm = new WeakMap > var person = {name: 'Bob'} undefined > var creditCard = {type: 'AMEX', number: 123456789} undefined > wm.set(person, creditCard) {} > wm.get(person) { type: 'AMEX', number: 123456789 }
Assim como no caso do Set, não há como obter o size
do WeakMap ou iterar sobre suas chaves ou valores:
> wm.size undefined > wm.forEach undefined
Quando o aplicativo deixa de ter uma referência forte ao person
, sua entrada em wm
poderia ser destruída, e o creditCard
poderia, por sua vez, ser destruído também. Leia mais sobre WeakMap e WeakSet.
for-of
Além do clássico for-in
clássico, o ES6 adicionou a declaração for-of
que permite iterar com sucesso os valores de arrays, iteráveis e geradores. Os dois últimos serão discutidos a seguir.
Aqui está for-of
iterando sobre uma matriz:
> var arr = [1, 2, 3] undefined > for (var n of arr) console.log(n) 1 2 3
Iteráveis e Iteradores
Portanto, o senhor também pode usar o for-of
para iterar sobre iteráveis.
Mas o que é um iterável?
Um iterável é um objeto que tem um método associado que inicializa e retorna um iterador. A forma como o senhor associa esse método a um objeto é:
var myObj = {} myObj[Symbol.iterator] = function(){ // I'll cover symbols later return new MyIterator }
Mas o que é um iterador?
Um iterador é um objeto que adere ao protocolo de iteradores – que requer apenas um método:
next()
– que avança para o próximo item da sequência toda vez que é chamado e retorna um objeto que contém duas propriedadesdone
– um booleano que é verdadeiro se e somente se a sequência já tiver terminadovalue
– o valor atual na sequência
Como exemplo, veja abaixo como eu consegui tornar iterável uma implementação simples de lista de links personalizada:
function LLNode(value){ this.value = value this.next = null } LLNode.prototype[Symbol.iterator] = function(){ var iterator = { next: next } var current = this function next(){ if (current){ var value = current.value var done = current == null current = current.next return { done: done, value: value } }else{ return { done: true } } } return iterator } var one = new LLNode(1) var two = new LLNode(2) var three = new LLNode(3) one.next = two two.next = three for (var i of one){ console.log(i) }
O resultado desse programa é
1 2 3
Geradores
Os geradores permitem que o senhor escreva um iterável de forma sucinta e facilmente compreensível. Eles também permitem que o senhor represente sequências infinitas.
Veja como eu poderia escrever um gerador que itera todos os números inteiros a partir de 0:
function *naturalNumbers(){ var n = 0 while (true){ yield n++ } }
Observe que o function *
e a sintaxe do yield
indicam que se trata de uma declaração do função geradora em vez de uma função normal. Quando o senhor chama uma função geradora, recebe de volta um gerador que implementa o protocolo do iterador:
> var gen = naturalNumbers() {} > gen.next() { value: 0, done: false } > gen.next() { value: 1, done: false }
Ele também é um iterável! O senhor pode verificar isso: se chamar seu método iterador, receberá de volta o próprio gerador:
> gen[Symbol.iterator]() === gen true
Mas a maneira mais eficiente de iterar sobre um iterável, é claro, é por meio da função for-of
declaração:
for (var n of naturalNumbers()){ console.log(n) }
Ops! Loop infinito (facepalm).
Os geradores também são interessantes porque são uma solução (entre várias) para o problema do callback hell. Notavelmente, co e koa são estruturas que fazem uso intenso de geradores, e ambas funcionam no io.js imediatamente;
Ler mais para obter tratamentos mais detalhados sobre os geradores.
Números binários e octais
Os números binários são prefixados com 0b
, e os números octais são prefixados com 0O
– ou seja, “zero” “O”.
console.log(0b100) console.log(0O100)
O programa acima produz resultados:
4 64
Promessas
O desenvolvimento de promessas foi um esforço muito popular, começando como bibliotecas ou componentes em várias estruturas. Atualmente, existem bibliotecas estabelecidas como RSVP, Qe Pássaro azul. A maioria das principais estruturas tem promessas incorporadas. Há um padrão para promessas chamado Promessas A+ ao qual a maioria das principais implementações aderem. Para completar, as promessas foram incorporadas ao próprio tempo de execução! A história por trás das promessas é bastante inspiradora.
Abaixo está um exemplo de como transformar uma biblioteca cliente http baseada em callback em uma função que retorna uma promessa:
var request = require('superagent') fetch('http://iojs.org') .then(function(reply){ console.log('Returned ' + reply.text.length + ' bytes.') }) function fetch(url){ return new Promise(function(resolve, reject){ request(url).end(function(err, reply){ if (err){ reject(err) }else{ resolve(reply) } }) }) }
As promessas também podem ser usadas de forma eficaz com geradores – que é a estratégia empregada pelo co. Ler este tutorial para obter uma explicação mais detalhada das promessas.
Novos métodos String
Alguns novos métodos foram adicionados à versão nativa do String
objeto.
-
String.fromCodePoint(number)
e.codePointAt(idx)
são comoString.fromCharCode
e.charCodeAt(idx)
exceto pelo fato de que eles suportam unicode e, portanto, os pontos de código alto são traduzidos em caracteres de vários bytes> s = String.fromCodePoint(194564) '你' > s.codePointAt(0) 194564
-
startsWith(s)
eendsWith(s)
> 'Hello, world!'.startsWith('Hello') true > 'Hello, world!'.endsWith('!') true
-
repeat(n)
> 'foobar'.repeat(5) 'foobarfoobarfoobarfoobarfoobar'
-
normalize()
– retorna o formulário de normalização unicode da string. Para realmente entender o que isso significa, leia sobre equivalência unicode.
Símbolos
O nome symbol
pode ser confuso porque esses símbolos não são como os de Ruby ou Smalltalk. Os símbolos no ES6 são usados como propriedades de objetos ocultos. Se o senhor for um Pythonista: pense em métodos mágicos com sublinhado duplo.
var secretMethod = Symbol('secret') var obj = {} obj[secretMethod] = function(){ return 'foobar' } obj[secretMethod]() // returns `foobar`
Agora, secretMethod
não aparecerá em um for-in
que percorre as propriedades do objeto. De fato, nenhuma propriedade de string corresponde ao símbolo referenciado por secretMethod
e não há como acessar o método sem ter uma referência ao símbolo. Há símbolos globais “bem conhecidos” no sistema, como Symbol.iterator
– que vimos ser usado para associar um objeto a seu iterador. O senhor pode fazer isso de qualquer maneira, leia mais sobre os símbolos.
Strings de modelo e strings de várias linhas
As strings de modelo são emprestadas da interpolação de strings do Ruby e do Perl. Isso evita que os desenvolvedores tenham que juntar pedaços de strings de forma desajeitada, o que geralmente resulta em muitas aspas.
> var name="Bobby" undefined > `Hello, ${name}!` 'Hello, Bobby!'
Observe que as cadeias de caracteres de modelo são delimitadas por traços ascendentes “`” em vez de aspas simples ou duplas. O que é interessante para mim é que agora o senhor pode escrever strings de várias linhas:
var age = 5 var sql = ` select name from people where age > ${age}; `
As strings de modelo têm mais um recurso: permitir que uma função personalizada avalie o modelo em questão. Isso é útil em situações que exigem escape de parâmetros específicos, como na higienização de parâmetros SQL para evitar ataques de injeção de SQL.
var age = 5 var sql = sqlSanitize` select name from people where age > ${age}; `
O senhor pode ler mais para tratamentos detalhados de strings de modelo.
Recursos notáveis por trás das bandeiras
Alguns dos recursos notáveis ainda estão marcados como em andamento no io.js – versão 1.0.3 no momento da redação deste texto – são:
Impressão geral
Estou otimista em relação ao estado dos recursos do ES6 no io.js. Gosto do fato de todos esses recursos funcionarem imediatamente, sem nenhum sinalizador especial. Mentalmente, essa designação torna esses recursos legítimos. Na maioria das vezes, quando esses recursos são usados de forma errada, as mensagens de erro lançadas são úteis para orientar os usuários. Os recursos que mais me entusiasmam são os geradores e as strings de modelo. Se eu estivesse iniciando um novo projeto de hobby hoje, com certeza daria uma chance ao io.js, brincaria, ficaria louco e experimentaria esses recursos na natureza.

Sobre Toby Ho
Toby é um desenvolvedor veterano de JavaScript. Ele gosta de ajudar os outros a aprender por meio de blogs, organizando encontros, dando workshops e ensinando em particular. Ele criou o executor de testes interativo Testem, que é seu trabalho de código aberto de maior orgulho até hoje.