Squish 6.6 ships with several extensions to the JavaScript support. The main ones are described below.
Let Declarations¶
Early JavaScript versions offered the var
keyword for variable declarations:
function factorial(n)
{
var result;
if (n > 1) {
var rest = factorial(n - 1);
result = rest * n;
} else {
result = 1;
}
return result;
}
The sometimes non-intuitive side-effect of var
declarations is their
scoping: they are accessible within the entire function's scope. Or
globally when found outside of a function. And - even more surprising -
access to the variable is possible before the declaration
statement. Even though the value will be undefined
in that case.
The let
keyword does away with those potential problems:
- The variable's life time is restricted to the current
{
...}
block scope. - Access before the declaration statement is not allow
x; // ReferenceError!
let x = 1;
if (x) {
let x = 2;
x; // <-- 2
}
x; // <-- 1
To further avoid variable declaration problems the "use strict"
directive described below is worthwhile using. It will catch cases of
accidental variable usage without a var
or let
declaration.
Const Declarations¶
The const
keyword was available before but had a behavior that
pre-dates the standardization in ECMAScript. As of Squish 6.6.0 const
will have
a) block scope like let
and
b) lead to an error on attempts to change its value
c; // ReferenceError!
const c = 1;
c = 2; // TypeError!
A constant declaration needs to include an initializer value,
i.e. const c;
by itself is not a valid statement.
Arrow Functions¶
A classic function declaration
function multiply(a, b)
{
return a * b;
}
print(multiply(3, 7)); // <-- 21
can be expressed in a short-hand form using the =>
operator:
let multiply = (a, b) => a * b;
print(multiply(3, 7)); // <-- 21
This notation is particularly convenient for concise expression of callback functions:
let arr = [ 3, 5 ];
arr.forEach(v => { test.log(v); }); // logs 3 and 5
Template Strings¶
Tired of assembling strings using the +
operator? A new type of
string literal marked by backticks provides more flexibility than the
classic strings surrounded by single or double quotes.
Instead, of assembling a constant like
const multiLine = "First line\n" +
"Second line\n" +
"Third line`;
multi-line strings can be expressed as a single literal for example:
const multiLine = `First line
Second line
Third line`;
And instead of mixing constant and variable parts like this
test.log("Found " + itemCount + " menu items");
the ${...}
placeholder can embed expressions that will be evaluated
on-the-fly:
test.log(`Found ${itemCount} menu items`);
Classes¶
Object-oriented programming with JavaScript is based on the concept of
function and prototype objects. A concise declaration of object
prototypes, functions and inheritance is now available via the class
keyword.
Note that the script interpreter has to see the declaration of a class prior to its first usage. That's different to functions that can be referenced even if the declaration follows later in the script.
Constructors¶
A class declaration can contain a special constructor
function. It
will be invoked upon creation of an object via the new
operator. That way an object's initial state can be set safely and
conveniently.
class Animal
{
constructor(name) { this.name = name; };
}
var dog = new Animal("Rantanplan");
dog.name; // "Rantanplan"
Prototype Methods¶
Function properties of class objects (methods) can be defined with a
shorthand notation that does not include the typical function
keyword:
class Animal
{
constructor(name) { this.name = name; };
jump() { return this.name + " jumps"; }
}
var dog = new Dog("Rantanplan");
dog.jump(); // "Rantanplan jumps"
Static Methods¶
Methods can be declared for the class itself via the static
keyword. They do not require instances of the class and not operate on
them.
Typically, class functions contain utility or factory functions.
class Animal
{
constructor(name) { this.name = name; };
static Dog(name)
{
let dog = new Animal(name);
dog.legs = 4;
return dog;
}
}
var dog = Animal.Dog("Rantanplan");
dog.legs; // 4
Extensions¶
Once a class is declared it can act as a base for other classes that will inherit all its properties.
class Bird extends Animal
{
chirp() { return this.name + " chirps" }
};
Super¶
The constructor
function of a complex class may want to invoke the
constructor of the base class. This is possible through the super()
function.
class Car {
constructor(brand) {
this.brand = brand;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
}
Similarly, the super
property references methods of the extended class:
class B { greet() { return "hel"; } }
class C extends B { greet() { return super.greet() + "lo"; } }
let c = new C();
c.greet(); // "hello"
Class Expressions¶
Classes can also be declared as part of an expression and thus treated like values:
let Animal = class { .... };
let animal = new Animal();
Strict Mode¶
A strict parsing mode will be enabled if the magic string "use strict"
or 'use strict'
is found at the top of a script file or
function. The strict mode helps to detect common programming errors
like access to undeclared variables.
Example:
"use strict";
function main() {
verboseMode = true; // <-- error: access to undeclared variable
}
Currently, the following issues will be detected:
- Access to undeclared variables
- Attempts to
delete
variables or constants - Usage of
with()
statement - Usage of legacy octal literals (e.g. 0123)
Both module code as well as class functions will always be interpreted in strict mode.
The magic "use strict"
string merely needs to be the first statement
within a file or function by the way. Both whitespace and comments can
come first.
Note about Script-based Object Maps¶
Since JavaScript modules will be evaluated in strict mode script-based object maps may need fixing in case they rely on behavior which is not permitted in strict mode.
Exponentiation Operator¶
A short form of the Math.pow(base, exp)
exponentiation function is
available via the new **
operator. It can also be part of an
assignment.
var n = 2 ** 3; // <--- 8
n **= 3; // <--- 512
Parameter-less Catch Clause¶
The classic way of catching a script exception in a try
/catch
statement includes the identification of the thrown exception - e
in
the example below:
try {
f();
} catch (e) {
test.log("Function f() threw an exception");
}
try {
f();
} catch {
test.log("Function f() threw an exception");
}
Miscellaneous¶
New style for octal literals (such as
0o123
and0O123
)The
Intl.DateTimeFormat().resolvedOptions()
function that will the localelocale
andtimeZone
configurationThe
Object.is(value1, value2)
comparison functionThe
Object.setPrototype(O, proto)
functionThe
Console
object was renamed toconsole
to be in line with what web browsers use. The object provides theassert()
function.Fixed the test method on JavaScript RegExp objects such that calls update the value of the lastIndex field if the global flag is specified.
The
Object.getPrototypeOf(O)
function now works with non-object values according to ECMAScript 2015.Syntax-checking of escape sequences in string literals is now more accurate.
Line continuations in JavaScript string literals now work as expected.