No results found

Your search did not match any results.

 

Java 9 | Excerpt

Nashorn JavaScript Engine in JDK 9

Handy additions and support for ES6 make Nashorn even more useful.

By Jim Laskey


Jim Laskey

Nashorn, the JDK’s built-in JavaScript engine, has undergone a variety of improvements in this new release. Before diving into those enhancements, let me briefly set the context for these changes so that their addition makes the most sense.

Background

When I started the development of Nashorn in late 2010, I was just looking for a way to experiment with the newly minted invokedynamic (JSR 292) byte-code instruction. The JVM team later adopted Nashorn as a test bed for invokedynamic, and the Nashorn Project drove much of the performance improvements made to the invokedynamic implementation.

While this was going on, the Java group was discussing 
how JavaScript would likely grow to dominate client-side development and that integrating JavaScript with Java would be a critical element of the client/server equation. Rhino—an open source implementation of JavaScript from the Mozilla Foundation that was then the JDK offering for JavaScript—was getting long in the tooth, and further development was winding down. In November 2012, JDK Enhancement Proposal (JEP) 174, “Nashorn JavaScript Engine,” was approved, which enabled work to begin in earnest to provide a fresh, robust, secure, full-featured implementation of ECMAScript-262 Edition 5.1 (ES5) to run on the Java platform.

Initially, Nashorn found a home in a wide variety of applications, such as app servers, JavaFX applications, utilities, shell scripts, embedded systems, and so on. 

Nashorn continues to have broad usage, but its use appears to have settled into three main areas:

  • The development of JavaScript applications that can be run on both the client and the server. In the JavaScript world, this is known as isomorphic development. The advantages are huge for smaller shops that want to build front ends for both desktop and mobile services—a single programming language with a common codebase and rapid delivery. Isomorphic development also scales well for larger systems.
  • Runtime adaptive or dynamic coding. The term I like to use is soft coding, where portions of an application can be modified after the application/server is deployed. This capability is used for everything from stored procedures in databases to application configuration management.
  • Shell scripting. This consists of using JavaScript in areas where bash or Python would traditionally be used.

There is often a lot of debate about Nashorn’s performance on the JVM compared to native JavaScript performance on platforms such as Google’s V8. Nashorn starts out slower because it translates the JavaScript to bytecode. After that, Nashorn is at the mercy of HotSpot to deliver native code. This approach works well for long-running server applications but not as well for small and run-once scripts. The main reason we developed Nashorn in the first place was to run JavaScript and Java together seamlessly. Most Nashorn applications do a great job of orchestrating JavaScript and Java, something that V8 was not designed to do.

ES6 Support

The most important issue for JavaScript developers doing isomorphic development is the need to have client/server source code compatibility. With most browsers adopting ECMAScript 6 (ES6) as the standard level of language support for JavaScript, it was essential to bring Nashorn in line. While the Nashorn team didn’t have time to deliver the complete ES6 feature set for the JDK 9 release, more ES6 features will follow in future updates. To activate ES6 support, use --language=es6 on the command line.

New keywords. Here is what you’ll find initially: the implementation of the new keywords, let and const, follow ES6 block scoping, with const creating an immutable local. For backward compatibility, var retains its ES5.1 semantics:

const a = 10;
a = 20; // TypeError trying to set a constant

let x = 10;
{
    let x = 20; // different scope
    print(x); // prints 20
}
print(x); // prints 10 from the outer scope

Support for symbols. Symbols are string-like objects introduced in ES6. They are primitives that are compared by reference instead of by value. This makes every symbol unique, which enables developers to create private object properties.

// a new, unique symbol
let unique = Symbol('optionalName');
myobj[unique] = 'foo';
// a shared symbol for the given name
let shared = Symbol.for('name');
myobj[shared] = 3;

The first example creates a distinct symbol, which can be used to create a property that is private to the current scope. The second example shows how symbols can be shared (interned) across an entire context. ES6 uses shared symbols to define iterators and default toString functions. Symbol-keyed properties are not exposed to any reflective operations.

New iterator protocol. ES6 provides a new protocol for iterating over objects:

// assign an iterator function to the
// Symbol.iterator property
myobj[Symbol.iterator] = function() {
     return {
        next: function() { ... }
     }
};
// Iterate over myobj using a for..of statement
for (let id of myobj) {
    print(myobj[id]);
}

Note the introduction of for..of loops. Nashorn’s syntax for each will still be available, but the team recommends switching to for..of even though they are functionally equivalent.

New collections. New collection classes were added in ES6 and in Nashorn: Map and Set. These collection classes implement the new iterator protocol.

let map = new Map();
map.set('foo', 'bar');
map.get('foo');  // -> 'bar'
map.clear();
map.get('foo');  // -> undefined

The weak reference versions of Map and Set have also been implemented; WeakMap and WeakSet. An entry in one of these collections is removed by the garbage collector when the entry value is no longer referenced by any other variable or object. 

Templates. Templates are a new form of string literals using back-ticks as delimiters, which allow embedded expressions and multiline strings. Nashorn also supports ES6 “tagged” strings rendered by a function.

// Multiline string
'string text line 1
 string text line 2'
// Embedded expression
'string text ${expression} string text'
// Rendered by function "tag"
tag 'string text ${expression} string text'

Note that in –scripting mode, back-ticks are still used for $EXEC expressions. 

Binary and octal numbers. Finally, there is a new syntax for binary and octal number literals.

// Binary number literal
0b111110111 === 503
// Octal number literal
0o767 === 503

In addition to these features from ES6, new capabilities enhance Nashorn’s usefulness. 


This article is excerpted from Java Magazine July/August 2017. Continue to the full article discussing the three other important features of Nashorn in JDK 9, including a new REPL.


Jim Laskey (@wickund) is a senior development manager in the Java Platform group at Oracle. Laskey has been a compiler-runtime developer since the mid-1970s and has worked at Symantec, Apple, and Azul Systems.