You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Next »

Nashorn Syntax Extensions

Nashorn implements ECMAScript 5.1 specification  http://www.ecma-international.org/ecma-262/5.1/

Nashorn implements number of syntactic and API extensions as well. This page describes syntax and API extensions of nashorn implementation.

Function expression closures

This Mozilla JavaScript 1.8 extension is also supported by Nashorn. This syntax allows braces and return keyword to be dropped when defining simple one-liner functions. Example:

Closure expression example
function sqr(x) x*x

// is equivalent to
// function sqr(x) { return x*x }

For each expressions

This is another Mozilla JavaScript 1.6 extension supported by Nashorn. ECMAScript for..in iterates over property names or array indices of an object. for..each..in loop iterates over property values of an object rather than property names/indices.

 

for each loop
for each (variable in object) { statement }

// print each array element 
var arr = [ "hello", "world" ];
for each (a in arr) {
 print(a)
}

New expression with last argument after ")"

This is another Rhino extension supported by Nashorn. In a new Constructor(x, y) expression, the last argument can be specified after ")" if it happens to be an object literal. Example:

new anonymous class-like syntax
// This syntax is primarily used to support anonymous class-like syntax for
// Java interface implementation as shown below.

var r = new java.lang.Runnable() {
    run: function() { print("run"); }
}

 

Anonymous function statements

Top-level function statements can be anonymous. Example:

 

anonymous function statements
function () {
    print("hello")
}

How do you call it then? Say if you had evaluated the above code by "eval" or script engine's "eval" call from Java, you can get the return value to be the function object - which can be invoked later.

Multi-line string literals (-scripting mode only)

Nashorn supports multi-line string literals with Unix shell's here-doc syntax. Example:

multi-line string literals
var str = <<EOF

This is a string that contains multiple lines
hello
world
That's all!

EOF

print(str)

 

String interpolation (-scripting mode only)

Expressions can be specified inside string literals with the syntax ${expression}. The string value is computed by substituting value of expressions for ${expression} in the string.

String expression interpolation
var x = "World"
var str = "Hello, ${x}"

print(str) // prints "Hello, World" because ${x} is substituted with value of variable "x"

Back-quote exec expressions (-scripting mode only)

Nashorn supports Unix shell like back quote strings. Back quoted strings are evaluated by executing the programs mentioned in the string and returning value produced by the 'exec'-ed program.

back quote exec strings
// exec "ls -l" to get file listing as a string
var files = `ls -l`
var lines = files.split("\n");

// print only the directories
for (var l in lines) {
    var line = lines[l];
    if (line.startsWith("d")) // directory
        print(line)
}

Nashorn script API extensions

__proto__ property

Like other ECMAScript implementations (like Rhino, v8) Nashorn supports mutable __proto__ magic property to read and write prototype of a given object. See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

Object.setPrototypeOf(obj, newProto)

ECMAScript specifies Object.getPrototypeOf(obj) function to get prototype of the given object. This nashorn specific extension allows prototype of an object to be set by newProto.

Object.bindProperties

Object.bindProperties lets you bind properties of one object to another object. Example:

Object.bindProperties
var obj = {}

var obj2 = { foo: 344 }

// bind properties of 'obj2' to 'obj'
Object.bindProperties(obj, obj2);

print(obj.foo);    // obj2.foo
obj.foo = "hello"  // obj2.foo assigned
print(obj2.foo);   // prints "hello"

// bind to global 'this' is also possible
Object.bindProperties(this, obj2);

print(foo);        // prints obj2.foo
foo = 42;          // assigns to obj2.foo
print(obj2.foo);   // prints 42


The bound object need not be a script object. It could be a Java object as well - usual Java bean style getter/setter properties will be bound. Also a property only with getter will be bound as read-only property.

Extensions of Error objects, Error.prototype and Error constructor

Nashorn extends ECMAScript Error (or subtype) objects with the following properties.

  • lineNumber - source code line number from which error object was thrown
  • columnNumber  -  source code column number from which error object was thrown
  • fileName  - source script file name
  • stack - script stack trace as a string

In addition to this Error.prototype has the following extension functions as well.

  • Error.prototype.printStackTrace() - prints full stack trace (including all Java frames) from where error was thrown from
  • Error.prototype.getStackTrace() -  returns an array of java.lang.StackTraceElement instance for ECMAScript frames only.

Error constructor includes dumpStack() function property

  • Error.dumpStack() - prints stack trace of the current thread - just like java.lang.Thread.dumpStack()

 

Error extensions
function func() {
    throw new Error()
}

function f() {
    func()
}

try {
    f()
} catch (e) {
    print(e.stack)
    print(e.lineNumber)
    print(e.columnNumber)
    print(e.fileName)
}

String.prototype extensions

String.prototype.trimLeft - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimLeft

String.prototype.trimRight - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimRight

Function.prototype.toSource

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toSource

Extension properties, functions in global object

__FILE__ , __LINE__, __DIR__

Current executing script file, line, directory of the script can be accessed by these global (read-only) properties. This is useful in debug/tracing scripts.

_FILE_ and _LINE_
print(__FILE__, __LINE__, __DIR__)

print function

print function prints it's arguments (after converting those to Strings) on standard output

print
print("hello", "world")

load function

Loads and evaluates script from a file or a URL or a script object. Examples:

load function
// can load script from files, URLs

load("foo.js"); // loads script from file "foo.js" from current directory
load("http://www.example.com/t.js"); // loads script file from given URL

// loads script from an object's properties. 

// Object should have "script" and "name" properties.
//     "script" property contains string code of the script. 
//     "name" property specifies name to be used while reporting errors from script
// This is almost like the standard "eval" except that it associates a name with
// the script string for debugging purpose.

load({ script: "print('hello')", name: "myscript.js"})

// load can also load from pseudo URLs like "nashorn:", "fx:". "nashorn:" pseudo URL scheme
// for nashorn's built-in scripts. "fx:" pseudo URL scheme for JavaFX support scripts

// load nashorn's parser support script - defines 'parse'
// function in global scope

load("nashorn:parser.js"); 

// load Mozilla compatibility script - which defines global functions
// like importPackage, importClass for rhino compatibility.

load("nashorn:mozilla_compat.js");

loadWithNewGlobal function

loadWithNewGlobal is almost like the function "load" in that it loads script from a file or a URL or a script object. But unlike 'load', loadWithNewGlobal creates a fresh ECMAScript global scope object and loads the script into it. The loaded script's global definitions go into the fresh global scope. Also, the loaded script's modifications of builtin objects (like String.prototype.indexOf) is not reflected in the caller's global scope – these are affected in the newly created global scope.

loadWithNewGlobal
loadWithNewGlobal({
    script: "foo = 333; print(foo)",
    name: "test"
});

// prints undefined as "foo" is defined in the new global and not here
print(typeof foo); 

exit and quit functions

These synonymous functions exit the current process with specified (optional) exit code.

exit
exit(1); // exit with given exit code
exit();  // exit 0
 
quit(2); // exit with given exit code
quit();  // exit 0

Packages, java, javax, javafx, com, edu

Packages and friends are there to support java package, class access from script. The properties of the Packages variable are all the top-level Java packages, such as java and javax etc.

Packages
var Vector = Packages.java.util.Vector;

// but short-cuts defined for important package prefixes like
//  Packages.java, Packages.javax, Packages.com, Packages.edu, Packages.javafx 

var JFrame = javax.swing.JFrame;
var List = java.util.List;
jjs session of Packages, classes
jjs> Packages.java
[JavaPackage java]
jjs> java
[JavaPackage java]
jjs> java.util.Vector
[JavaClass java.util.Vector]
jjs> javax
[JavaPackage javax]
jjs> javax.swing.JFrame
[JavaClass javax.swing.JFrame]

 

 

  • No labels