ES6 Overview in 350 Bullet Points
I heard you like bullet points, so I made an article containing hundreds of those bad boys. To kick things off, here’s a table of contents with all the topics covered. It has bullet points in it — obviously. Note that if you want these concepts to permeate your brain, you’ll have a much better time learning the subject by going through the in-depth series and playing around, experimenting with ES6 code yourself.
Table of Contents
Apologies about that long table of contents, and here we go.
Introduction
- ES6 — also known as Harmony,
es-next
, ES2015 — is the latest finalized specification of the language - The ES6 specification was finalized in June 2015.(hence ES2015)
- Future versions of the specification will follow the
ES[YYYY]
pattern, e.g ES2016 for ES7- Yearly release schedule, features that don’t make the cut take the next train
- Since ES6 pre-dates that decision, most of us still call it ES6
- Starting with ES2016 (ES7), we should start using the
ES[YYYY]
pattern to refer to newer versions - Top reason for naming scheme is to pressure browser vendors into quickly implementing newest features
(back to table of contents)
Tooling
- To get ES6 working today, you need a JavaScript-to-JavaScript transpiler
- Transpilers are here to stay
- They allow you to compile code in the latest version into older versions of the language
- As browser support gets better, we’ll transpile ES2016 and ES2017 into ES6 and beyond
- We’ll need better source mapping functionality
- They’re the most reliable way to run ES6 source code in production today (although browsers get ES5)
- Babel (a transpiler) has a killer feature: human-readable output
- Use
babel
to transpile ES6 into ES5 for static builds - Use
babelify
to incorporatebabel
into your Gulp, Grunt, ornpm run
build process - Use Node.js
v4.x.x
or greater as they have decent ES6 support baked in, thanks tov8
- Use
babel-node
with any version ofnode
, as it transpiles modules into ES5 - Babel has a thriving ecosystem that already supports some of ES2016 and has plugin support
- Read A Brief History of ES6 Tooling
(back to table of contents)
Assignment Destructuring
var {foo} = pony
is equivalent tovar foo = pony.foo
var {foo: baz} = pony
is equivalent tovar baz = pony.foo
- You can provide default values,
var {foo='bar'} = baz
yieldsfoo: 'bar'
ifbaz.foo
isundefined
- You can pull as many properties as you like, aliased or not
var {foo, bar: baz} = {foo: 0, bar: 1}
gets youfoo: 0
andbaz: 1
- You can go deeper.
var {foo: {bar}} = { foo: { bar: 'baz' } }
gets youbar: 'baz'
- You can alias that too.
var {foo: {bar: deep}} = { foo: { bar: 'baz' } }
gets youdeep: 'baz'
- Properties that aren’t found yield
undefined
as usual, e.g:var {foo} = {}
- Deeply nested properties that aren’t found yield an error, e.g:
var {foo: {bar}} = {}
- It also works for arrays,
[a, b] = [0, 1]
yieldsa: 0
andb: 1
- You can skip items in an array,
[a, , b] = [0, 1, 2]
, gettinga: 0
andb: 2
- You can swap without an “aux” variable,
[a, b] = [b, a]
- You can also use destructuring in function parameters
- Assign default values like
function foo (bar=2) {}
- Those defaults can be objects, too
function foo (bar={ a: 1, b: 2 }) {}
- Destructure
bar
completely, likefunction foo ({ a=1, b=2 }) {}
- Default to an empty object if nothing is provided, like
function foo ({ a=1, b=2 } = {}) {}
- Assign default values like
- Read ES6 JavaScript Destructuring in Depth
(back to table of contents)
Spread Operator and Rest Parameters
- Rest parameters is a better
arguments
- You declare it in the method signature like
function foo (... everything) {}
everything
is an array with all parameters passed tofoo
- You can name a few parameters before
. everything
, likefunction foo (bar, ... rest) {}
- Named parameters are excluded from
. rest
. rest
must be the last parameter in the list
- You declare it in the method signature like
- Spread operator is better than magic, also denoted with
.
syntax- Avoids
.apply
when calling methods,fn(... [1, 2, 3])
is equivalent tofn(1, 2, 3)
- Easier concatenation
[1, 2...[3, 4, 5] 6, 7]
- Casts array-likes or iterables into an array, e.g
[...document.querySelectorAll('img')]
- Useful when destructuring too,
[a, , ...rest] = [1, 2, 3, 4, 5]
yieldsa: 1
andrest: [3, 4, 5]
- Makes
new
+.apply
effortless,new Date(... [2015, 31, 8])
- Avoids
- Read ES6 Spread and Butter in Depth
(back to table of contents)
Arrow Functions
- Terse way to declare a function like
param => returnValue
- Useful when doing functional stuff like
[1, 2].map(x => x * 2)
- Several flavors are available, might take you some getting used to
p1 => expr
is okay for a single parameterp1 => expr
has an implicitreturn
statement for the providedexpr
expression- To return an object implicitly, wrap it in parenthesis
() => ({ foo: 'bar' })
or you’ll get an error - Parenthesis are demanded when you have zero, two, or more parameters,
() => expr
or(p1, p2) => expr
- Brackets in the right-hand side represent a code block that can have multiple statements,
() = > {}
- When using a code block, there’s no implicit
return
, you’ll have to provide it —() => { return 'foo' }
- You can’t name arrow functions statically, but runtimes are now much better at inferring names for most methods
- Arrow functions are bound to their lexical scope
this
is the samethis
context as in the parent scopethis
can’t be modified with.call
..apply
, or similar “reflection”-type methods
- Read ES6 Arrow Functions in Depth
(back to table of contents)
Template Literals
- You can declare strings with
`
(backticks), in addition to"
and'
- Strings wrapped in backticks are template literals
- Template literals can be multiline
- Template literals allow interpolation like
`ponyfoo.com is ${rating}`
whererating
is a variable - You can use any valid JavaScript expressions in the interpolation, such as
` ` ${2 * 3}
or`${foo()}`
- You can use tagged templates to change how expressions are interpolated
- Add a
fn
prefix tofn`foo, ${bar} and ${baz}`
fn
is called once withtemplate, ... expressions
template
is['foo, ', ' and ', '']
andexpressions
is[bar, baz]
- The result of
fn
becomes the value of the template literal - Possible use cases include input sanitization of expressions, parameter parsing, etc.
- Add a
- Template literals are almost strictly better than strings wrapped in single or double quotes
- Read ES6 Template Literals in Depth
(back to table of contents)
Object Literals
- Instead of
{ foo: foo }
, you can just do{ foo }
— known as a property value shorthand - Computed property names,
{ [prefix + 'Foo']: 'bar' }
, whereprefix: 'moz'
, yields{ mozFoo: 'bar' }
- You can’t combine computed property names and property value shorthands,
{ [foo] }
is invalid - Method definitions in an object literal can be declared using an alternative, more terse syntax,
{ foo () {} }
- See also
Object
section - Read ES6 Object Literal Features in Depth
(back to table of contents)
Classes
- Not “traditional” classes, syntax sugar on top of prototypal inheritance
- Syntax similar to declaring objects,
class Foo {}
- Instance methods —
new Foo().bar
— are declared using the short object literal syntax,class Foo { bar () {} }
- Static methods —
Foo.isPonyFoo()
— need astatic
keyword prefix,class Foo { static isPonyFoo () {} }
- Constructor method
class Foo { constructor () { /* initialize instance */ } }
- Prototypal inheritance with a simple syntax
class PonyFoo extends Foo {}
- Read ES6 Classes in Depth
(back to table of contents)
Let and Const
let
andconst
are alternatives tovar
when declaring variableslet
is block-scoped instead of lexically scoped to afunction
let
is hoisted to the top of the block, whilevar
declarations are hoisted to top of the function- “Temporal Dead Zone” — TDZ for short
- Starts at the beginning of the block where
let foo
was declared - Ends where the
let foo
statement was placed in user code (hoisiting is irrelevant here) - Attempts to access or assign to
foo
within the TDZ (before thelet foo
statement is reached) result in an error - Helps prevent mysterious bugs when a variable is manipulated before its declaration is reached
- Starts at the beginning of the block where
const
is also block-scoped, hoisted, and constrained by TDZ semanticsconst
variables must be declared using an initializer,const foo = 'bar'
- Assigning to
const
after initialization fails silently (or loudly — with an exception — under strict mode) const
Variables don’t make the assigned value immutableconst foo = { bar: 'baz' }
meansfoo
will always reference the right-hand side objectconst foo = { bar: 'baz' }; foo.bar = 'boo'
won’t throw
- Declaration of a variable by the same name will throw
- Meant to fix mistakes where you reassign a variable and lose a reference that was passed along somewhere else
- In ES6, functions are block scoped
- Prevents leaking block-scoped secrets through hoisting,
{ let _foo = 'secret', bar = () => _foo; }
- Doesn’t break user code in most situations, and typically what you wanted anyways
- Prevents leaking block-scoped secrets through hoisting,
- Read ES6 Let, Const and the “Temporal Dead Zone” (TDZ) in Depth
(back to table of contents)
Symbols
- A new primitive type in ES6
- You can create your own symbols using
var symbol = Symbol()
- You can add a description for debugging purposes, like
Symbol('ponyfoo')
- Symbols are immutable and unique.
Symbol()
.Symbol()
.Symbol('foo')
andSymbol('foo')
are all different - Symbols are of type
symbol
, thus:typeof Symbol() === 'symbol'
- You can also create global symbols with
Symbol.for(key)
- If a symbol with the provided
key
already existed, you get that one back - Otherwise, a new symbol is created, using
key
as its description as well Symbol.keyFor(symbol)
is the inverse function, taking asymbol
and returning itskey
- Global symbols are as global as it gets, or cross-realm. Single registry used to look up these symbols across the runtime
window
contexteval
context</code> context, <code>Symbol.for('foo') === iframe.contentWindow.Symbol.for('foo')</code></li> </ul></li> </ul></li> <li>There's also "well-known" symbols <ul> <li>Not on the global registry, accessible through <code>Symbol[name]</code>, e.g: <code>Symbol.iterator</code></li> <li>Cross-realm, meaning <code>Symbol.iterator === iframe.contentWindow.Symbol.iterator</code></li> <li>Used by specification to define protocols, such as the <a href="https://github.com/bevacqua/es6#iterators"><em>iterable</em> protocol</a> over <code>Symbol.iterator</code></li> <li>They're not <strong>actually well-known</strong> -- in colloquial terms</li> </ul></li> <li>Iterating over symbol properties is hard, but not impossible and definitely not private <ul> <li>Symbols are hidden to all pre-ES6 "reflection" methods</li> <li>Symbols are accessible through <code>Object.getOwnPropertySymbols</code></li> <li>You won't stumble upon them but you <strong>will</strong> find them if <em>actively looking</em></li> </ul></li> <li>Read <a href="https://ponyfoo.com/articles/es6-symbols-in-depth" title="ES6 Symbols in Depth on Pony Foo">ES6 Symbols in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#iterators"></a>Iterators</h2> <ul> <li>Iterator and iterable protocol define how to iterate over any object, not just arrays and array-likes</li> <li>A well-known <code>Symbol</code> is used to assign an iterator to any object</li> <li><code>var foo = { [<mark>Symbol.iterator</mark>]: iterable}</code>, or <code>foo[<mark>Symbol.iterator</mark>] = iterable</code></li> <li>The <code>iterable</code> is a method that returns an <code>iterator</code> object that has a <code>next</code> method</li> <li>The <code>next</code> method returns objects with two properties, <code>value</code> and <code>done</code> <ul> <li>The <code>value</code> property indicates the current value in the sequence being iterated</li> <li>The <code>done</code> property indicates whether there are any more items to iterate</li> </ul></li> <li>Objects that have a <code>[Symbol.iterator]</code> value are <em>iterable</em>, because they subscribe to the iterable protocol</li> <li>Some built-ins like <code>Array</code>, <code>String</code>, or <code>arguments</code> -- and <code>NodeList</code> in browsers -- are iterable by default in ES6</li> <li>Iterable objects can be looped over with <code>for..of</code>, such as <code>for (let el of document.querySelectorAll('a'))</code></li> <li>Iterable objects can be synthesized using the spread operator, like <code>[...document.querySelectorAll('a')]</code></li> <li>You can also use <code>Array.from(document.querySelectorAll('a'))</code> to synthesize an iterable sequence into an array</li> <li>Iterators are <em>lazy</em>, and those that produce an infinite sequence still can lead to valid programs</li> <li>Be careful not to attempt to synthesize an infinite sequence with <code>...</code> or <code>Array.from</code> as that <strong>will</strong> cause an infinite loop</li> <li>Read <a href="https://ponyfoo.com/articles/es6-iterators-in-depth" title="ES6 Iterators in Depth on Pony Foo">ES6 Iterators in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#generators"></a>Generators</h2> <ul> <li>Generator functions are a special kind of <em>iterator</em> that can be declared using the <code><mark>function*</mark> generator () {}</code> syntax</li> <li>Generator functions use <code>yield</code> to emit an element sequence</li> <li>Generator functions can also use <code>yield*</code> to delegate to another generator function <em>-- or any iterable object</em></li> <li>Generator functions return a generator object that's adheres to both the <em>iterable</em> and <em>iterator</em> protocols <ul> <li>Given <code>g = generator()</code>, <code>g</code> adheres to the iterable protocol because <code>g[Symbol.iterator]</code> is a method</li> <li>Given <code>g = generator()</code>, <code>g</code> adheres to the iterator protocol because <code>g.next</code> is a method</li> <li>The iterator for a generator object <code>g</code> is the generator itself: <code>g[Symbol.iterator]() === g</code></li> </ul></li> <li>Pull values using <code>Array.from(g)</code>, <code>[...g]</code>, <code>for (let item of g)</code>, or just calling <code>g.next()</code></li> <li>Generator function execution is suspended, remembering the last position, in four different cases <ul> <li>A <code>yield</code> expression returning the next value in the sequence</li> <li>A <code>return</code> statement returning the last value in the sequence</li> <li>A <code>throw</code> statement halts execution in the generator entirely</li> <li>Reaching the end of the generator function signals <code>{ done: true }</code></li> </ul></li> <li>Once the <code>g</code> sequence has ended, <code>g.next()</code> simply returns <code>{ done: true }</code> and has no effect</li> <li>It's easy to make asynchronous flows feel synchronous <ul> <li>Take user-provided generator function</li> <li>User code is suspended while asynchronous operations take place</li> <li>Call <code>g.next()</code>, unsuspending execution in user code</li> </ul></li> <li>Read <a href="https://ponyfoo.com/articles/es6-generators-in-depth" title="ES6 Generators in Depth on Pony Foo">ES6 Generators in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#promises"></a>Promises</h2> <ul> <li>Follows the <a href="https://promisesaplus.com/" title="An open standard for sound, interoperable JavaScript promises"><code>Promises/A+</code></a> specification, was widely implemented in the wild before ES6 was standarized <em>(e.g <a href="https://github.com/petkaantonov/bluebird" title="petkaantonov/bluebird on GitHub"><code>bluebird</code></a>)</em></li> <li>Promises behave like a tree. Add branches with <code>p.then(handler)</code> and <code>p.catch(handler)</code></li> <li>Create new <code>p</code> promises with <code>new Promise(<mark>(resolve, reject) => { /* resolver */ }</mark>)</code> <ul> <li>The <code>resolve(value)</code> callback will fulfill the promise with the provided <code>value</code></li> <li>The <code>reject(reason)</code> callback will reject <code>p</code> with a <code>reason</code> error</li> <li>You can call those methods asynchronously, blocking deeper branches of the promise tree</li> </ul></li> <li>Each call to <code>p.then</code> and <code>p.catch</code> creates another promise that's blocked on <code>p</code> being settled</li> <li>Promises start out in <em>pending</em> state and are <strong>settled</strong> when they're either <em>fulfilled</em> or <em>rejected</em></li> <li>Promises can only be settled once, and then they're settled. Settled promises unblock deeper branches</li> <li>You can tack as many promises as you want onto as many branches as you need</li> <li>Each branch will execute either <code>.then</code> handlers or <code>.catch</code> handlers, never both</li> <li>A <code>.then</code> callback can transform the result of the previous branch by returning a value</li> <li>A <code>.then</code> callback can block on another promise by returning it</li> <li><code>p.catch(fn).catch(fn)</code> won't do what you want -- unless what you wanted is to catch errors in the error handler</li> <li><a href="https://ponyfoo.com/articles/es6-promises-in-depth#using-promiseresolve-and-promisereject"><code>Promise.resolve(value)</code></a> creates a promise that's fulfilled with the provided <code>value</code></li> <li><a href="https://ponyfoo.com/articles/es6-promises-in-depth#using-promiseresolve-and-promisereject"><code>Promise.reject(reason)</code></a> creates a promise that's rejected with the provided <code>reason</code></li> <li><a href="https://ponyfoo.com/articles/es6-promises-in-depth#leveraging-promiseall-and-promiserace"><code>Promise.all(...promises)</code></a> creates a promise that settles when all <code>...promises</code> are fulfilled or 1 of them is rejected</li> <li><a href="https://ponyfoo.com/articles/es6-promises-in-depth#leveraging-promiseall-and-promiserace"><code>Promise.race(...promises)</code></a> creates a promise that settles as soon as 1 of <code>...promises</code> is settled</li> <li>Use <a href="http://bevacqua.github.io/promisees/" title="Promisees — Promise visualization playground for the adventurous">Promisees</a> -- the promise visualization playground -- to better understand promises</li> <li>Read <a href="https://ponyfoo.com/articles/es6-promises-in-depth" title="ES6 Promises in Depth">ES6 Promises in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#maps"></a>Maps</h2> <ul> <li>A replacement to the common pattern of creating a hash-map using plain JavaScript objects <ul> <li>Avoids security issues with user-provided keys</li> <li>Allows keys to be arbitrary values, you can even use DOM elements or functions as the <code>key</code> to an entry</li> </ul></li> <li><code>Map</code> adheres to <em><a href="https://github.com/bevacqua/es6#iterators">iterable</a></em> protocol</li> <li>Create a <code>map</code> using <code>new Map()</code></li> <li>Initialize a map with an <code>iterable</code> like <code>[[key1, value1], [key2, value2]]</code> in <code>new Map(iterable)</code></li> <li>Use <code>map.set(key, value)</code> to add entries</li> <li>Use <code>map.get(key)</code> to get an entry</li> <li>Check for a <code>key</code> using <code>map.has(key)</code></li> <li>Remove entries with <code>map.delete(key)</code></li> <li>Iterate over <code>map</code> with <code>for (let [key, value] of map)</code>, the spread operator, <code>Array.from</code>, etc</li> <li>Read <a href="https://ponyfoo.com/articles/es6-maps-in-depth" title="ES6 Maps in Depth on Pony Foo">ES6 Maps in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#weakmaps"></a>WeakMaps</h2> <ul> <li>Similar to <code>Map</code>, but not quite the same</li> <li><code>WeakMap</code> isn't iterable, so you don't get enumeration methods like <code>.forEach</code>, <code>.clear</code>, and others you had in <code>Map</code></li> <li><code>WeakMap</code> keys must be reference types. You can't use value types like symbols, numbers, or strings as keys</li> <li><code>WeakMap</code> entries with a <code>key</code> that's the only reference to the referenced variable are subject to garbage collection</li> <li>That last point means <code>WeakMap</code> is great at keeping around metadata for objects, while those objects are still in use</li> <li>You avoid memory leaks, without manual reference counting -- think of <code>WeakMap</code> as <a href="https://msdn.microsoft.com/en-us/library/system.idisposable%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396" title="IDisposable on MSDN"><code>IDisposable</code></a> in .NET</li> <li>Read <a href="https://ponyfoo.com/articles/es6-weakmaps-sets-and-weaksets-in-depth#es6-weakmaps" title="ES6 WeakMaps, Sets, and WeakSets in Depth on Pony Foo">ES6 WeakMaps in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#sets"></a>Sets</h2> <ul> <li>Similar to <code>Map</code>, but not quite the same</li> <li><code>Set</code> doesn't have keys, there's only values</li> <li><code>set.set(value)</code> doesn't look right, so we have <code>set.add(value)</code> instead</li> <li>Sets can't have duplicate values because the values are also used as keys</li> <li>Read <a href="https://ponyfoo.com/articles/es6-weakmaps-sets-and-weaksets-in-depth#es6-sets" title="ES6 WeakMaps, Sets, and WeakSets in Depth on Pony Foo">ES6 Sets in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#weaksets"></a>WeakSets</h2> <ul> <li><code>WeakSet</code> is sort of a cross-breed between <code>Set</code> and <code>WeakMap</code></li> <li>A <code>WeakSet</code> is a set that can't be iterated and doesn't have enumeration methods</li> <li><code>WeakSet</code> values must be reference types</li> <li><code>WeakSet</code> may be useful for a metadata table indicating whether a reference is actively in use or not</li> <li>Read <a href="https://ponyfoo.com/articles/es6-weakmaps-sets-and-weaksets-in-depth#es6-weaksets" title="ES6 WeakMaps, Sets, and WeakSets in Depth on Pony Foo">ES6 WeakSets in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#proxies"></a>Proxies</h2> <ul> <li>Proxies are created with <code>new Proxy(target, handler)</code>, where <code>target</code> is any object and <code>handler</code> is configuration</li> <li>The default behavior of a <code>proxy</code> acts as a passthrough to the underlying <code>target</code> object</li> <li>Handlers determine how the underlying <code>target</code> object is accessed on top of regular object property access semantics</li> <li>You pass off references to <code>proxy</code> and retain strict control over how <code>target</code> can be interacted with</li> <li>Handlers are also known as traps, these terms are used interchangeably</li> <li>You can create <strong>revocable</strong> proxies with <code>Proxy.revocable(target, handler)</code> <ul> <li>That method returns an object with <code>proxy</code> and <code>revoke</code> properties</li> <li>You could <a href="https://github.com/bevacqua/es6#destructuring">destructure</a> <code>var <mark>{proxy, revoke}</mark> = Proxy.revocable(target, handler)</code> for convenience</li> <li>You can configure the <code>proxy</code> all the same as with <code>new Proxy(target, handler)</code></li> <li>After <code>revoke()</code> is called, the <code>proxy</code> will <strong>throw</strong> on <em>any operation</em>, making it convenient when you can't trust consumers</li> </ul></li> <li><a href="https://ponyfoo.com/articles/es6-proxies-in-depth#get"><code>get</code></a> -- traps <code>proxy.prop</code> and <code>proxy['prop']</code></li> <li><a href="https://ponyfoo.com/articles/es6-proxies-in-depth#set"><code>set</code></a> -- traps <code>proxy.prop = value</code> and <code>proxy['prop'] = value</code></li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#has"><code>has</code></a> -- traps <code>in</code> operator</li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#deleteproperty"><code>deleteProperty</code></a> -- traps <code>delete</code> operator</li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#defineproperty"><code>defineProperty</code></a> -- traps <code>Object.defineProperty</code> and declarative alternatives</li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#enumerate"><code>enumerate</code></a> -- traps <code>for..in</code> loops</li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#ownkeys"><code>ownKeys</code></a> -- traps <code>Object.keys</code> and related methods</li> <li><a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth#apply"><code>apply</code></a> -- traps <em>function calls</em></li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#construct"><code>construct</code></a> -- traps usage of the <code>new</code> operator</li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#getprototypeof"><code>getPrototypeOf</code></a> -- traps internal calls to <code>[[GetPrototypeOf]]</code></li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#setprototypeof"><code>setPrototypeOf</code></a> -- traps calls to <code>Object.setPrototypeOf</code></li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#isextensible"><code>isExtensible</code></a> -- traps calls to <code>Object.isExtensible</code></li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#preventextensions"><code>preventExtensions</code></a> -- traps calls to <code>Object.preventExtensions</code></li> <li><a href="https://ponyfoo.com/articles/morees6-proxy-traps-in-depth#getownpropertydescriptor"><code>getOwnPropertyDescriptor</code></a> -- traps calls to <code>Object.getOwnPropertyDescriptor</code></li> <li>Read <a href="https://ponyfoo.com/articles/es6-proxies-in-depth" title="ES6 Proxies in Depth on Pony Foo">ES6 Proxies in Depth</a></li> <li>Read <a href="https://ponyfoo.com/articles/es6-proxy-traps-in-depth" title="ES6 Proxy Traps in Depth on Pony Foo">ES6 Proxy Traps in Depth</a></li> <li>Read <a href="https://ponyfoo.com/articles/more-es6-proxy-traps-in-depth" title="More ES6 Proxy Traps in Depth on Pony Foo">More ES6 Proxy Traps in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#reflection"></a>Reflection</h2> <ul> <li><code>Reflection</code> is a new static built-in (think of <code>Math</code>) in ES6</li> <li><code>Reflection</code> methods have sensible internals, e.g <code>Reflect.defineProperty</code> returns a boolean instead of throwing</li> <li>There's a <code>Reflection</code> method for each proxy trap handler, and they represent the default behavior of each trap</li> <li>Going forward, new reflection methods in the same vein as <code>Object.keys</code> will be placed in the <code>Reflection</code> namespace</li> <li>Read <a href="https://ponyfoo.com/articles/es6-reflection-in-depth" title="ES6 Reflection in Depth on Pony Foo">ES6 Reflection in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#number"></a><code>Number</code></h2> <ul> <li>Use <code>0b</code> prefix for binary, and <code>0o</code> prefix for octal integer literals</li> <li><code>Number.isNaN</code> and <code>Number.isFinite</code> are like their global namesakes, except that they <em>don't</em> coerce input to <code>Number</code></li> <li><code>Number.parseInt</code> and <code>Number.parseFloat</code> are exactly the same as their global namesakes</li> <li><code>Number.isInteger</code> checks if input is a <code>Number</code> value that doesn’t have a decimal part</li> <li><code>Number.EPSILON</code> helps figure out negligible differences between two numbers -- e.g. <code>0.1 + 0.2</code> and <code>0.3</code></li> <li><code>Number.MAX_SAFE_INTEGER</code> is the largest integer that can be safely and precisely represented in JavaScript</li> <li><code>Number.MIN_SAFE_INTEGER</code> is the smallest integer that can be safely and precisely represented in JavaScript</li> <li><code>Number.isSafeInteger</code> checks whether an integer is within those bounds, able to be represented safely and precisely</li> <li>Read <a href="https://ponyfoo.com/articles/es6-number-improvements-in-depth" title="ES6 Number Improvements in Depth on Pony Foo">ES6 <code>Number</code> Improvements in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#math"></a><code>Math</code></h2> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#array"></a><code>Array</code></h2> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#object"></a><code>Object</code></h2> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#strings-and-unicode"></a>Strings and Unicode</h2> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <h2><a href="https://github.com/bevacqua/es6#modules"></a>Modules</h2> <ul> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#strict-mode">Strict Mode</a> is turned on by default in the ES6 module system</li> <li>ES6 modules are files that <a href="https://ponyfoo.com/articles/es6-modules-in-depth#export"><code>export</code></a> an API</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#exporting-a-default-binding"><code>export default value</code></a> exports a default binding</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#named-exports"><code>export var foo = 'bar'</code></a> exports a named binding</li> <li>Named exports are bindings that <a href="https://ponyfoo.com/articles/es6-modules-in-depth#bindings-not-values">can be changed</a> at any time from the module that's exporting them</li> <li><code>export { foo, bar }</code> exports <a href="https://ponyfoo.com/articles/es6-modules-in-depth#exporting-lists">a list of named exports</a></li> <li><code>export { foo <mark>as ponyfoo</mark> }</code> aliases the export to be referenced as <code>ponyfoo</code> instead</li> <li><code>export { foo <mark>as default</mark> }</code> marks the named export as the default export</li> <li>As <a href="https://ponyfoo.com/articles/es6-modules-in-depth#best-practices-and-export">a best practice</a>, <code>export default api</code> at the end of all your modules, where <code>api</code> is an object, avoids confusion</li> <li>Module loading is implementation-specific, allows interoperation with CommonJS</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#import"><code>import 'foo'</code></a> loads the <code>foo</code> module into the current module</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#importing-default-exports"><code>import <mark>foo from</mark> 'ponyfoo'</code></a> assigns the default export of <code>ponyfoo</code> to a local <code>foo</code> variable</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#importing-named-exports"><code>import {foo, bar} from 'baz'</code></a> imports named exports <code>foo</code> and <code>bar</code> from the <code>baz</code> module</li> <li><code>import {foo <mark>as bar</mark>} from 'baz'</code> imports named export <code>foo</code> but aliased as a <code>bar</code> variable</li> <li><code>import {default} from 'foo'</code> also imports the default export</li> <li><code>import {default <mark>as bar</mark>} from 'foo'</code> imports the default export aliased as <code>bar</code></li> <li><code>import foo, {bar, baz} from 'foo'</code> mixes default <code>foo</code> with named exports <code>bar</code> and <code>baz</code> in one declaration</li> <li><a href="https://ponyfoo.com/articles/es6-modules-in-depth#import-all-the-things"><code>import * as foo from 'foo'</code></a> imports the namespace object <ul> <li>Contains all named exports in <code>foo[name]</code></li> <li>Contains the default export in <code>foo.default</code>, if a default export was declared in the module</li> </ul></li> <li>Read <a href="https://ponyfoo.com/articles/es6-modules-in-depth" title="ES6 Modules in Depth on Pony Foo">ES6 Modules Additions in Depth</a></li> </ul> <p><sup><a href="https://github.com/bevacqua/es6#table-of-contents">(back to table of contents)</a></sup></p> <p>Time for a bullet point detox. Then again, I <em>did warn you</em> to read the <a href="https://ponyfoo.com/articles/tagged/es6-in-depth" title="ES6 in Depth on Pony Foo">article series</a> instead. Don't forget to subscribe and maybe even <a href="http://patreon.com/bevacqua" title="My Patreon Account">contribute to keep Pony Foo alive</a>. Also, did you try the <a href="https://en.wikipedia.org/wiki/Konami_Code">Konami code</a> just yet?</p> </article> </div>
- If a symbol with the provided