io.js – slavný fork Node.js nedávno vydal svou první verzi se sloganem „Přinášíme ES6 do komunity uzlů!“. io.js dostal tyto funkce před Node.js tím, že agresivně sledoval nejnovější verze V8 JavaScript motoru. Jako cizinec, který se dívá dovnitř, jsem si vzal pár hodin na to, abych se v tom pohrabal, a zde oznámím svá zjištění.
Instalace
Binární distribuce io.js jsou k dispozici na jejich titulní stránce a můžete si stáhnout binární soubor pro Linux, Windows, Mac nebo jej sestavit ze zdroje. Binární instalační programy však přepíší node
a npm
spustitelné soubory ve vašem systému, pokud máte nainstalovaný Node.js. Proto doporučuji použít nvm k instalaci io.js bezkonfliktně. Instalace nvm je docela snadná, pokud jste to ještě neudělali. Pokud a kdy máte nvm, jednoduše to udělejte
$ nvm install io.js ######################################################################## 100.0% WARNING: checksums are currently disabled for io.js Now using io.js v1.0.3
Zkontrolujte, zda to fungovalo:
$ iojs >
Voilà! Všimněte si, že node
má alias iojs
a npm
se stále nazývá npm
.
Přehled funkcí ES6
Ačkoli někteří lidé již ES6 nějakou dobu používají prostřednictvím transpilerů, když pracuji s transpilovaným kódem, mám pocit, jako bych musel současně ladit dvě verze kódu – ladění je dost obtížné s jedinou verzí . Z tohoto důvodu je pro mě nativní podpora mnohem přitažlivější.
Stránka io.js ES6 poskytuje informace o změnách, které provedli v podpoře ES6 v enginu. Zrušili --harmony
příznak - který jste v Node 0.11+ museli zahrnout, pokud jste vůbec chtěli používat nějaké funkce ES6. V io.js je získáte hned po vybalení! Aktuální seznam funkcí ES6 povolených ve výchozím nastavení je:
let
prohlášeníconst
prohlášeníMap
aSet
WeakMap
aWeakSet
- Generátory
- Binární a osmičkové literály
- Sliby
- Některé další metody řetězců
- Symboly
- Řetězce šablon
Přidali také --es_staging
příznak, který vám umožní získat přístup k funkcím, které jsou hotové, ale ještě nebyly dobře otestovány. U funkcí, které se právě implementují, byste museli získat přístup ke každé funkci jednotlivě pomocí příznaku harmonie, který jí odpovídá. Seznam příznaků funkcí harmonie můžete získat prostřednictvím:
$ 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")
Nyní přejdeme k jednotlivým funkcím.
let
a const
let
a const
příkazy jsou dostupné pouze v přísném režimu. Zadejte tedy "use strict"
v horní části každého souboru JS, kde je chcete použít.
let
příkaz je náhradou za var
výraz, který má lexikální rozsah. To znamená, že zatímco proměnná je definována pomocí var
je viditelný pro funkci, ve které je deklarován, let
je viditelný pouze pro blok kódu, ve kterém je deklarován. V JavaScriptu je blok kódu složený příkaz uzavřený v {
a }
který obsahuje nula nebo více příkazů. Bloky kódu běžně používáte v příkazech if, cyklech for, cyklech while a jako tělo definice funkce. Je však také možné napsat samostatný blok kódu.
Zde je příklad let
:
"use strict" if (player.partner){ let partner = player.partner // do stuff with partner here } console.log(parter) // this throws partner is not defined
Zde je let
ve smyčce for:
"use strict" for (let i = 0; i < 10; i++){ console.log(i) } console.log(i) // this throws i is not defined
const
je jako let
kromě toho, že jakmile je proměnná deklarována, nelze ji znovu přiřadit jiné hodnotě.
"use strict" const ITERATIONS_TO_RUN = 10 ITERATIONS_TO_RUN = 12 // throws TypeError: Assignment to constant variable.
Mapa a sada
ES6 představil Map
a Set
datové struktury pro vaše pohodlí. Možná se teď ptáte, proč vůbec potřebujeme mapu? Co je špatného na používání objektových literálů jako map? No, argumentovalo se, že objekt není hash (nebo er mapa). Krátká verze je taková, že objekt zdědí všechny Object.prototype
vlastnosti, což je ve většině případů nežádoucí, pokud jej chcete použít jako mapu.
Nyní je zde příklad použití 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
A tady je Set in action:
> 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 a WeakSet
WeakMap
a WeakSet
jsou nové datové typy, které zrcadlí Map
a Set
, ale na rozdíl od Map
a Set
- které lze implementovat jako polyfilly - ty lze implementovat pouze nativně. Slovo „slabé“ odkazuje na slabé reference . Slabá reference je odkaz na objekt, který garbage collector ignoruje. Pokud existují pouze slabé reference – žádné další silné reference – ukazující na předmětný objekt, pak může být tento objekt zničen a jeho paměť opuštěna.
Pojďme se bavit o WeakSet
za prvé - protože je to jednodušší vysvětlit. A WeakSet
's API je podmnožinou Set
's. Nemůžete do něj však uložit primitivní hodnoty:
> var ws = new WeakSet undefined > ws.add(1) TypeError: Invalid value used in weak set
To dává smysl, protože primitivní hodnoty jsou uloženy hodnotou, nikoli odkazem, a nemělo by smysl ani mluvit o slabých odkazech. Místo toho do něj budete muset vložit objekty:
> 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
nemá size
vlastnost nebo způsob iterace jejích členů
> ws.size undefined > ws.forEach(function(item){ console.log('WeakSet has ' + item)}) TypeError: undefined is not a function > ws.forEach undefined
Je to právě proto, že reference jsou slabé, a jako takové by mohly být objekty zničeny bez předchozího upozornění, v tomto okamžiku by k nim již nebylo možné získat přístup. Jedno z možných použití WeakSet
je uložit sadu souvisejících prvků DOM bez obav z úniku paměti, když jsou prvky z dokumentu odstraněny.
A WeakMap
je jako Map
kromě toho, že všechny jeho klíče jsou slabé reference. Nesmí to být ani primitivní hodnoty.
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 }
Stejně jako u Set neexistuje žádný způsob, jak získat size
WeakMap nebo iterujte přes její klíče nebo hodnoty:
> wm.size undefined > wm.forEach undefined
Když aplikace přestane obsahovat silný odkaz na person
, jeho záznam v wm
mohl být zničen a creditCard
může být také zničen. Přečtěte si více o WeakMap a WeakSet.
for-of
Kromě klasického for-in
ES6 přidal for-of
příkaz, který vám umožní stručně iterovat hodnoty polí, iterovatelných položek a generátorů. Poslední dva budou diskutovány níže.
Zde je for-of
iterace přes pole:
> var arr = [1, 2, 3] undefined > for (var n of arr) console.log(n) 1 2 3
Iterátory a iterátory
Můžete tedy také použít for-of
příkaz iterovat přes iterovatelné.
Iterovatelný je objekt, který má přidruženou metodu, která inicializuje a vrací iterátor. Způsob přiřazení této metody k objektu je:
var myObj = {} myObj[Symbol.iterator] = function(){ // I'll cover symbols later return new MyIterator }
Iterátor je objekt, který dodržuje protokol iterátoru – což vyžaduje pouze jednu metodu:
next()
- která při každém zavolání postoupí na další položku v pořadí a vrátí objekt, který obsahuje dvě vlastnostidone
- boolean, který je pravdivý tehdy a jen tehdy, když sekvence již skončilavalue
- aktuální hodnota v sekvenci
Níže je uveden příklad, jak se mi podařilo vytvořit iterovatelnou jednoduchou vlastní implementaci seznamu odkazů:
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) }
Výstupem tohoto programu je
1 2 3
Generátory
Generátory vám umožňují psát iterovatelnou výstižným a snadno srozumitelným způsobem. Umožňuje také reprezentovat nekonečné sekvence.
Zde je návod, jak bych mohl napsat generátor, který iteruje všechna celá čísla počínaje 0:
function *naturalNumbers(){ var n = 0 while (true){ yield n++ } }
Všimněte si function *
syntaxe a yield
příkaz – tyto označují, že se jedná o funkci generátoru spíše než normální funkce. Když zavoláte funkci generátoru, získáte zpět generátor, který implementuje protokol iterátoru:
> var gen = naturalNumbers() {} > gen.next() { value: 0, done: false } > gen.next() { value: 1, done: false }
Je to také opakovatelné! Můžete si to ověřit:pokud zavoláte jeho metodu iterátoru, dostanete zpět samotný generátor:
> gen[Symbol.iterator]() === gen true
Ale přesnější způsob, jak iterovat přes iterovatelný, je samozřejmě přes for-of
prohlášení:
for (var n of naturalNumbers()){ console.log(n) }
Jejda! Nekonečná smyčka (facepalm).
Generátory jsou také skvělé, protože je to jedno řešení (mezi několika) problému zpětného volání. Co a koa jsou rámce, které intenzivně využívají generátory a oba fungují v io.js ihned po vybalení. Podrobnější zpracování generátorů naleznete v dalším textu.
Binární a osmičková čísla
Binární čísla mají předponu 0b
a osmičkové číslice mají předponu 0O
- tedy "nula" "O".
console.log(0b100) console.log(0O100)
Výše uvedené výstupy programu:
4 64
Sliby
Vývoj příslibů byl do značné míry snahou zdola, začínal jako knihovny nebo komponenty v různých rámcích. Dnes existují zavedené knihovny jako RSVP, Q a Bluebird. Většina hlavních rámců má vestavěné sliby. Existuje standard pro sliby nazvaný Promises A+, který většina hlavních implementací dodržuje. Aby toho nebylo málo, sliby byly přeneseny do samotného běhového prostředí! Příběh za sliby je docela inspirativní.
Níže je uveden příklad, jak přeměnit knihovnu klienta http založenou na zpětném volání na funkci, která vrací příslib:
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) } }) }) }
Sliby lze také efektivně využít s generátory – což je strategie, kterou spol. Přečtěte si tento návod, kde najdete podrobnější vysvětlení slibů.
Nové metody řetězců
Do nativního String
byly přidány některé nové metody objekt.
-
String.fromCodePoint(number)
a.codePointAt(idx)
jsou jakoString.fromCharCode
a.charCodeAt(idx)
kromě toho, že podporují unicode, a proto se vysoké kódové body převádějí do vícebajtových znaků> s = String.fromCodePoint(194564) '你' > s.codePointAt(0) 194564
-
startsWith(s)
aendsWith(s)
> 'Hello, world!'.startsWith('Hello') true > 'Hello, world!'.endsWith('!') true
-
repeat(n)
> 'foobar'.repeat(5) 'foobarfoobarfoobarfoobarfoobar'
-
normalize()
- vrátí formulář normalizace unicode struny. Abyste skutečně pochopili, co to znamená, přečtěte si o ekvivalenci unicode.
Symboly
Název symbol
může být matoucí, protože tyto symboly nejsou jako ty v Ruby nebo Smalltalku. Symboly v ES6 se používají jako skryté vlastnosti objektů. Pokud jste Pythonista:přemýšlejte o magických metodách dvojitého podtržení.
var secretMethod = Symbol('secret') var obj = {} obj[secretMethod] = function(){ return 'foobar' } obj[secretMethod]() // returns `foobar`
Nyní secretMethod
nezobrazí se v rámci for-in
procházet vlastnostmi objektu. Ve skutečnosti žádná vlastnost řetězce neodpovídá symbolu, na který odkazuje secretMethod
a neexistuje způsob, jak přistupovat k metodě bez odkazu na symbol. V systému jsou globální "dobře známé" symboly jako Symbol.iterator
- který jsme viděli použít k přidružení objektu k jeho iterátoru. V každém případě si přečtěte více o symbolech.
Řetězce šablon a víceřádkové řetězce
Řetězce šablony jsou vypůjčeny z interpolace řetězců Ruby a Perlu. Ušetří to vývojářům, aby museli nešikovně sčítat kousky řetězců – což často vede ke spoustě uvozovek.
> var name = 'Bobby' undefined > `Hello, ${name}!` 'Hello, Bobby!'
Všimněte si, že řetězce šablony jsou uzavřeny znaménky "`" spíše než jednoduchými nebo dvojitými uvozovkami - budete muset sáhnout nahoru levým malíčkem. Co je pro mě vzrušující je, že nyní můžete psát víceřádkové řetězce:
var age = 5 var sql = ` select name from people where age > ${age}; `
Řetězce šablon mají ještě jednu vlastnost – umožnit vlastní funkci vyhodnotit danou šablonu. To je užitečné v situacích, které vyžadují specifické escapování parametrů – například při dezinfekci parametrů SQL, aby se zabránilo útokům SQL injection.
var age = 5 var sql = sqlSanitize` select name from people where age > ${age}; `
Můžete si přečíst více o hloubkovém zpracování řetězců šablony.
Významné funkce za vlajkami
Některé z významných funkcí jsou stále označeny jako probíhající v io.js – verze 1.0.3 v době psaní tohoto článku – jsou:
- moduly –
--harmony_modules
- funkce šipek –
--harmony_arrow_functions
- proxy –
--harmony_proxies
- třídy –
--harmony_classes
Celkový dojem
Cítím se optimisticky ohledně stavu funkcí ES6 na io.js. Líbí se mi, že všechny tyto funkce fungují hned po vybalení bez zvláštních příznaků. Mentálně toto označení činí tyto vlastnosti legitimními. Většinou, když jsou tyto funkce používány nesprávným způsobem, jsou vržené chybové zprávy užitečné při vedení uživatelů. Funkce, ze kterých jsem nejvíce nadšený, jsou generátory a řetězce šablon. Kdybych dnes začínal s novým hobby projektem, určitě bych zkusil io.js, zahrál si, šel do divočiny a vyzkoušel tyto funkce v divočině.