ArangoDB 2.4 will be shipped with an updated version of V8.
The V8 version included in 2.4 will be 3.29.59. This version will replace the almost two year old 3.16.14. A lot of things happened in V8 since then, and a lot of ES6 features have been added to it.
ES6 is not finalized yet, and support for it is a work in progress on all platforms.
ES6 provides many cool features that can make JavaScript developer’s life easier. In this blog post, I’ll summarize a few ES6 features that are available in ArangoDB, either for scripting purposes in the ArangoShell, or in your server-side Foxx actions inside the database.
I don’t want to put you off until Doomsday. ArangoDB 2.4 should be released next week. Time to play with some ES6 features!
Summary for the impatient
The following ES6 features are available in ArangoDB 2.4 by default:
- iterators
- the
of
operator - symbols
- predefined collections types (Map, Set etc.)
- typed arrays
Many other ES6 features are disabled by default, but can be made available by starting arangod or arangosh with the appropriate options:
- arrow functions
- proxies
- generators
- String, Array, and Number enhancements
- constants
- enhanced object and numeric literals
To activate all these ES6 features, start arangod or arangosh with the following options:
arangosh --javascript.v8-options="--harmony --harmony_generators"
Activating ES6 features
Work on ES6, also dubbed Harmony or ES.next, is still in progress. At the time of this writing, the ES6 specification was still in draft status.
Therefore no platform has implemented all ES6 features yet. And because ES6 is still a moving target, the already implemented features should still be considered experimental.
This is true for all environments that implement ES6 features. For example, Firefox and other browsers contain lots of experimental ES6 features already, providing a notice that these might change in future versions.
V8 is no exception here. It has turned most ES6 features off by default, but it provides several command-line options to turn them on explicitly.
The V8 version used for ArangoDB 2.4 provides the following ES6-related switches:
--harmony_scoping
(enable harmony block scoping)--harmony_modules
(enable harmony modules (implies block scoping))--harmony_proxies
(enable harmony proxies)--harmony_generators
(enable harmony generators)--harmony_numeric_literals
(enable harmony numeric literals (0o77, 0b11))--harmony_strings
(enable harmony string)--harmony_arrays
(enable harmony arrays)--harmony_arrow_functions
(enable harmony arrow functions)--harmony_classes
(enable harmony classes)--harmony_object_literals
(enable harmony object literal extensions)--harmony
(enable all harmony features (except proxies))
These switches are all off by default. To turn on features for either arangod
or arangosh, start it with the V8 option(s) wrapped into the ArangoDB option
--javascript.v8-options
, e.g.:
arangosh --javascript.v8-options="--harmony_proxies --harmony_generators --harmony_array"
On a side note: node.js is also using V8. Turning on ES6 features in node.js almost
works the same way. Just omit the surrounding --javascript.v8-options="..."
:
node --harmony_proxies --harmony_generators --harmony_array
Note that the V8 options can only be set for the entire process (i.e. arangosh, arangod or node.js), and not just for a specific script or application. In reality this shouldn’t be too problematic as the vast majority of ES6 features is downwards-compatible to ES5.1.
ES6 features by example
Following I have listed a few select ES6 features that are usable in ArangoDB 2.4, in no particular order. I have omitted a few ES6 features that aren’t supported in bundled V8 version, and also omitted classes and modules due to lack of time.
Arrow functions
ES6 provides an optional arrow function syntax. The arrow function syntax is a shorthand for writing a full-blown function declaration. Here’s an example:
1 2 3 4 5 |
|
Arrow functions can also take multiple parameters. The syntax then becomes:
1 2 3 4 5 |
|
So far we have only seen arrow functions with simple expressions, but arrow function bodies can also be more complex and can contain multiple statements:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Arrow functions are turned off by default. To enable them in arangod or arangosh, start them
with the option --javascript.v8-options="--harmony_arrow_functions"
.
Maps and sets
ES6 maps provide a specialized alternative to regular objects in case a lookup-by-key functionality is required.
When no maps are available, storing keys mapped to objects is normally done using a plain object. With ES6, the same use case can be handled with using a Map object:
1 2 3 4 5 6 |
|
ES6 maps can be more efficient than plain objects in some cases. For the above case of storing 5M entries, an ES6 map is about twice as fast as a plain object on my laptop. Though there might be cases we are plain objects are still faster.
There’s more to ES6 Maps than just efficiency:
- ES6 maps provide a member
size
which keeps track of the number of objects in the map. This is hard to achieve with a plain object. - Objects can only have string keys, whereas map keys can have different key types.
- They don’t inherit keys from the prototype, so there is no
hasOwnProperty
hassle with Maps.
ES6 also comes with a specialized Set object. The Set object is a good alternative to plain JavaScript objects when the use case is to track unique values. Using a Set is more intuitive, potentially more efficient and may require even less memory than when implementing the same functionality with a plain JavaScript object:
1 2 3 4 5 6 |
|
Maps and sets are enabled by default in arangod and arangosh. No special configuration is needed to use them in your code.
Proxy objects
Proxy objects can be used to intercept object property accesses at runtime. This can be used for meta-programming in many real-world situations, e.g.:
- preventing, auditing and logging property accesses
- calculated / derived properties
- adding a compatibility layer on top of an object
Here’s an example that logs property accesses on the proxied object:
1 2 3 4 5 6 7 8 9 10 11 |
|
Proxy objects are not available by default. To enable them in arangod or arangosh, start them
with the option --javascript.v8-options="--harmony_proxies"
.
Iterators and generators
ES6 provides generators and iterators. They can be used individually or in combination.
Let’s start with a simple example of a generator that will generate only two values:
1 2 3 4 5 6 7 8 9 |
|
As can be seen above, the value yielded by the generator function will be returned
wrapped into an object with a value
and a done
attribute automatically.
The general pattern to consume all values from a generator function is to call
its next()
method until its done
value is true
:
1 2 3 4 5 6 7 8 9 |
|
An alternative to that is to use an iterator (note the new of
operator):
1 2 3 4 5 |
|
Generator functions produce their values lazily. Therefore it is possible and not inefficent to write generators that produce never-ending sequences. Though one must be careful to abort iterating over the generator values at some point if the sequence does not terminate:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
We have now seen two uses of iterators as part of the previous examples.
As demoed, generator function values can be iterated with the of
operator
without any further ado. Apart from generators, a few other built-in types
also provide ready-to-use iterators. The most prominent are String
and Array
:
1 2 3 4 5 |
|
The above example will iterate all the individual characters of the string.
The following example iterates the values of an Array:
1 2 3 4 5 |
|
This will produce "this"
, "is"
, "a"
, "test"
. This is normally what is
desired when iterating over the values of an Array. Compare this to the in
operator which would produce 0
, 1
, 2
and 3
instead.
Map and Set objects also implement iterators:
1 2 3 4 5 6 7 8 9 10 11 |
|
Note that Maps also provide dedicated iterators for just their keys or their values:
1 2 3 4 5 6 7 |
|
Rolling an iterator for your own object is also possible by implementing the method
Symbol.iterator
for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Generators and iterators are not available by default. To enable them in arangod
or arangosh, start them with the option --javascript.v8-options="--harmony_generators"
.
String enhancements
ES6 provides the following convenience string functions:
- string.startsWith(what)
- string.endsWith(what)
- string.includes(what)
- string.repeat(count)
- string.normalize(method)
- string.codePointAt(position)
- String.fromCodePoint(codePoint)
These functions are mostly self-explaining, so I won’t explain them in more
detail here. Apart from that, these functions are turned off by default.
To enable them in arangod or arangosh, start them with the option
--javascript.v8-options="--harmony_strings"
.
Array enhancements
ES6 provides the following enhancements for the Array
object:
- array.find(function)
- array.findIndex(function)
- array.keys()
- array.values()
- Array.observe(what, function)
Here are a few examples demoing these functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
The Array enhancements are turned off by default. To enable them in arangod or
arangosh, start them with the option --javascript.v8-options="--harmony_arrays"
.
Number enhancements
The Number
object is extended with the following ES6 functions:
- Number.isInteger(value)
- Number.isSafeInteger(value)
There are also Number.MIN_SAFE_INTEGER
and Number.MAX_SAFE_INTEGER
so applications
can programmatically check whether a numeric value can still be stored in the range of
-253 to +253 without potential precision loss.
Constants
The const
keyword can be used to define a read-only constant. The constant must be
initialized and a variable with the same name should not be redeclared in the same scope.
Here is an example of using const
:
1 2 3 4 |
|
In non-strict mode, const
variables behave non-intuitively. Re-assigning a value
to a variable declared const
does not throw an exception, but the assignment will
not be carried out either. Instead, the assignment will silently fail and the const
variable will keep its original value:
1 2 3 4 5 |
|
1 2 3 4 5 |
|
The const
keyword is disabled by default. To enable it in arangod or arangosh,
start them with the option --javascript.v8-options="--harmony_scoping"
.
Enhanced object literals
ES6 provides a shorthand for defining methods in object literals.
The following example creates a normal method named save
in myObject
:
1 2 3 4 5 6 |
|
Interestingly, the object literals seem to work for method declarations only. I did not get them to work for non-method object properties, though ES6 allows that. It seems that this is not implemented in V8 yet.
Enhanced object literals are turned off by default. To enable them in arangod
or arangosh, start them with the option --javascript.v8-options="--harmony_object_literals"
.
Enhanced numeric literals
For the ones that love working with binary- or octal-encoded numbers, ES6 has support for this too:
1 2 |
|
Enhanced numeric literals are turned off by default. To enable them in arangod
or arangosh, start them with the option --javascript.v8-options="--harmony_numeric_literals"
.
Symbols
ES6 also provides a Symbol type. Symbols are created using the global Symbol()
function.
Each time this function is called, a new Symbol object will be created.
A Symbol can be given an optional name, but this name cannot be used to identify the
Symbol later. However, Symbols can be compared by identity.
What one normally wants is to use the same Symbol from different program parts. In this
case, a Symbol should not be created with the Symbol()
function, but with Symbol.for()
.
This will register the Symbol in a global symbol table if it is not there yet, and return
the Symbol if already created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Symbol object properties are not enumerated by default, so they can be used to implement “hidden” or internal properties.
Symbols can be used by default in arangod and arangosh. No special configuration is required.
TypedArrays
TypedArrays are Arrays whose members all have the same type and size. They are more
specialized (read: limited but efficient) alternatives to the all-purpose Array
type.
TypedArrays look and feel a bit like C arrays, and they are often used as an Array-like view into binary data (for which JavaScript has no native support).
A TypedArray is created (and all of its memory is allocated) by invoking the appropriate TypedArray constructor:
- Int8Array
- Uint8Array
- Uint8ClampedArray
- Int16Array
- Uint16Array
- Int32Array
- Uint32Array
- Float32Array
- Float64Array
1 2 3 4 5 6 |
|
1 2 3 4 5 6 |
|
TypedArrays can be used in arangod and arangosh by default. No special configuration is required to activate them.
Unsupported ES6 features
As mentioned before, V8 does not yet support every proposed ES6 feature. For example, the following ES6 features are currently missing:
- template strings
- function default parameters
- rest function parameter
- spread operator
- destructuring
- array comprehension
let
I strongly hope these features will make it into the final version of ES6 and will be implemented by the V8 team in future versions of V8.
Apart from that, a lot of nice ES6 features are there already and can be used in ArangoDB applications.