diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc index 3a2f0e4..0d2e12e 100644 --- a/chapters/ch02.asciidoc +++ b/chapters/ch02.asciidoc @@ -1,4 +1,4 @@ -[[ecmascript6-essentials]] +[[es6-essentials]] == ES6 Essentials The sixth edition of the language comes with a plethora of non-breaking syntax improvements, most of which we'll tackle throughout this chapter. Many of these changes are syntactic sugar, that is: they could be represented in ES5, albeit using more complicated pieces of code. There are also changes that aren't merely syntactic sugar but a completely different way of declaring variables using `let` and `const`, as we'll see towards the end of the chapter. diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc index 2b97368..1620d41 100644 --- a/chapters/ch03.asciidoc +++ b/chapters/ch03.asciidoc @@ -1,5 +1,5 @@ -[[classes-symbols-and-symbols]] -== Classes, Symbols, and Objects +[[classes-symbols-objects-and-objects]] +== Classes, Symbols, Objects, and Decorators Now that we've covered the basic improvements to the syntax, we're in good shape to take aim at a few other additions to the language: classes, and symbols. Classes provide syntax to represent prototypal inheritance under the traditional class-based programming paradigm. Symbols are a new primitive value type in JavaScript, like strings, booleans, and numbers. They can be used for defining protocols, and in this chapter we'll investigate what that means. When we're done with classes and symbols, we'll discuss a few new static methods added to the `Object` built-in in ES6. @@ -879,3 +879,65 @@ ____ ==== In the following chapter we'll look at more features coming in ES6 and how they can be used to iterate over any JavaScript objects, as well as how to master flow control using promises and generators. + +=== 3.4 Decorators + +Decorators are, as most things programming, definitely not a new concept. They pattern is fairly commonplace in modern programming languages: you have attributes in C#, they're called annotations in Java, there's decorators in Python, and the list goes on. There's a JavaScript decorators proposalfootnoteref:[decorators,You can find the proposal draft online at: https://mjavascript.com/out/decorators.] in the works. It is currently sitting at stage 2 of the TC39 process. + +==== 3.4.1 A Primer on JavaScript Decorators + +The syntax for JavaScript decorators is fairly similar to that of Python decorators. JavaScript decorators may be applied to classes and any statically-defined properties, such as those found on an object literal declaration or in a `class` declaration -- even if they are `get` accessors, `set` accessors, or `static` properties. + +The proposal defines a decorator as an `@` followed by a sequence of dotted identifiersfootnoteref:[no-dynamic-access, Accessing properties via `[]` notation is disallowed due to the difficulty it would present when disambiguating grammar at the compiler level.] and an optional argument list. Here's a few examples. + +- `@decorators.frozen` is a valid decorator +- `@decorators.frozen(true)` is a valid decorator +- `@decorators().frozen()` is a syntax error +- `@decorators['frozen']` is a syntax error + +Zero or more decorators can be attached to `class` declarations and class members. + +[source,javascript] +---- +@inanimate +class Car {} + +@expensive +@speed('fast') +class Lamborghini extends Car {} + +class View { + @throttle(200) // reconcile once every 200ms at most + reconcile() {} +} +---- + +Decorators are implemented by way of functions. Member decorator functions take a member descriptor and return a member descriptor. + +In the following example we define a `readonly` member decorator function which makes decorated members non-writable. + +[source,javascript] +---- +function readonly(member) { + member.descriptor.writable = false +} +---- + +Class decorator functions take a `target`, which is the class constructor being decorated; a `heritage` parameter, containing the parent class when the decorated class extends another class; and a `members` array, with a list of member descriptors for the class being decorated. + +We could implement a class-wide `readonlyMembers` decorator by reusing the `readonly member decorator on each member descriptor for a decorated class, as shown next. + +[source,javascript] +---- +function readonlyMembers(target, heritage, members) { + members.forEach(member => readonly(member)) +} +---- + +==== 3.4.2 Stacking Decorators and a Warning about Immutability + +With all the fluff around immutability you may be tempted to return a new property descriptor from your decorators, without modifying the original descriptor. While well-intentioned, this may have an undesired effect, as it is possible to decorate the same `class` or class member several times. + +If any decorators in a piece of code returned an entirely new `descriptor` without taking into consideration the `descriptor` parameter they receive, they'd effectively lose all the decoration that took place before the different descriptor was returned. + +We should be careful to write decorators that take into account the supplied `descriptor`: modify it directly or create one that's based on the `descriptor` that's provided to you. diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc index ef90b03..6b853ed 100644 --- a/chapters/ch05.asciidoc +++ b/chapters/ch05.asciidoc @@ -1,4 +1,4 @@ -[[leveraging-es-collections]] +[[leveraging-ecmascript-collections]] == Leveraging ECMAScript Collections JavaScript data structures are flexible enough that we're able to turn any object into a hash-map, where we map string keys to arbitrary values. For example, one might use an object to map npm package names to their metadata, as shown next. diff --git a/chapters/ch07.asciidoc b/chapters/ch07.asciidoc index de4bc60..18c1260 100644 --- a/chapters/ch07.asciidoc +++ b/chapters/ch07.asciidoc @@ -1,4 +1,4 @@ -[[built-in-improvements]] +[[built-in-improvements-in-es6]] == Built-in Improvements in ES6 Thus far in the book, we've discussed entirely new language syntax, such as property value shorthands, arrow functions, destructuring, or generators; and entirely new built-ins, such as `WeakMap`, `Proxy`, or `Symbol`. This chapter, on the other hand, is mostly devoted to existing built-ins that were improved in ES6. These improvements consist mostly of new instance methods, properties, and utility methods. diff --git a/images/c03g01-props-gump.png b/images/c03g01-props-gump.png new file mode 100644 index 0000000..336b3ea Binary files /dev/null and b/images/c03g01-props-gump.png differ