# New in JavaScript 1.7

Revision Information
• Revision slug: JavaScript/New_in_JavaScript/1.7
• Revision title: New in JavaScript 1.7
• Revision id: 51805
• Created:
• Creator: Sheppy
• Is reviewed? Yes
• Reviewed:
• Reviewed by: Jay
• Is approved? Yes
• Is current revision? No
• Comment Fixed to match final syntax; made examples work.

## Revision Content

Please note that this document is a work in progress. Some of the new features it covers are not implemented yet, so syntax may change.

JavaScript 1.7 is a language update introducing several new features, in particular generators, iterators, array comprehensions, `let` expressions, and destructuring assignment. It also includes all the features of JavaScript 1.6.

JavaScript 1.7 support should be available in Firefox 2 beta 1 and later.

The code samples included in this article can be experimented with in the JavaScript shell. Read Introduction to the JavaScript shell to learn how to build and use the shell.

## Generators and iterators

When developing code that involves an iterative algorithm (such as iterating over a list, or repeatedly performing computations on the same data set), there are often state variables whose values need to be maintained for the duration of the computation process. Traditionally, you have to use a callback function to obtain the intermediate values of an iterative algorithm.

### Generators

Consider this iterative algorithm that computes Fibonacci numbers:

```function do_callback(num) {
print(num);
}

function fib() {
var i = 0, j = 1, n = 0;
while (n < 10) {
do_callback(i);
var t = i;
i = j;
j += t;
n++;
}
}

fib();
```

This code uses a callback routine to perform operations on each iterative step of the algorithm. In this case, each Fibonacci number is simply printed to the console.

Generators and iterators work together to provide a new, better, way to do this. Let's see how the Fibonacci number routine looks written using a generator:

```function fib() {
var i = 0, j = 1;
while (true) {
yield i;
var t = i;
i = j;
j += t;
}
}

var g = fib();
for (var i = 0; i < 10; i++) {
print(g.next());
}
```

The function containing the `yield` keyword is a generator. When you call it, its formal parameters are bound to actual arguments, but its body isn't actually evaluated. Instead, a generator-iterator is returned. Each call to the generator-iterator's `next()` method performs another pass through the iterative algorithm. Each step's value is the value specified by the `yield` keyword. Think of `yield` as the generator-iterator version of `return`, indicating the boundary between each iteration of the algorithm. Each time you call `next()`, the generator code resumes from the statement following the `yield`.

You cycle a generator-iterator by repeatedly calling its `next()` method until you reach your desired result condition. In this example, we can obtain however many Fibonacci numbers we want by continuing to call `g.next()` until we have the number of results we want.

### Iterators

An iterator is a special object that lets you iterate over data.

Here's a simple example:

```var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
while(true) {
print(it.next());
}
} catch(err) {
if (err != StopIteration) {
print("Unknown error: " + err.description + "\n");
}
}
print("End of record.\n");
```

You can create an iterator for an object by calling `Iterator(objectname)`. Once you have an iterator, you can easily fetch the next item in the object by calling the iterator's `next()` method.

If there is no data left, the `StopIteration` exception is thrown.

The output from this program looks like this:

```name,Jack Bauer
id,12345
agency,CTU
region,Los Angeles
End of record.
```

You can, optionally, specify a second parameter when creating your iterator, which is a boolean value that indicates whether or not you only want the keys returned each time you call its `next()` method. Changing `var it = Iterator(obj);` to `var it = Iterator(obj, true);` in the above sample results in the following output:

```name
id
agency
region
End of record.
```

Iterators are a handy way to scan through the data in objects, including objects whose content may include data you're unaware of. This can be particularly useful if you need to preserve data your application isn't expecting.

## Array comprehensions

Array comprehensions are a use of generators that provides a convenient way to perform powerful initialization of arrays. For example:

```function range(begin, end) {
for (let i = begin; i < end; ++i) {
yield i;
}
}
```

`range()` is a generator that returns all the values between <tt>begin</tt> and <tt>end</tt>. Having defined that, we can use it like this:

```var ten_squares = [i * i for (i in range(0, 10))];
```

This pre-initializes a new array, ten_squares, to contain the squares of the values in the range `0..9`.

You can use any conditional when initializing the array. If you want to initialize an array to contain the even numbers between 0 and 20, you can use this code:

```var evens = [i for (i in range(0, 21)) if (i % 2 == 0)];
```

Prior to JavaScript 1.7, this would have to be coded something like this:

```var evens = [];
for (var i=0; i <= 20; i++) {
if (i % 2 == 0)
evens.push(i);
}
```

Not only is the array comprehension much more compact, but it's actually easier to read, once you're familiar with the concept.

#### Scoping rules

Array comprehensions have an implicit block around them, containing everything inside the square brackets, as well as implicit `let` declarations.

## Block scope with `let`

### The `let` statement

The `let` statement provides local scoping for variables, constants, and functions, and is intended to be used in place of `var`. It works by binding zero or more variables to a single block of code. The completion value of the `let` statement is the completion value of the block.

For example:

```var x = 5;
var y = 0;

let (x = x+10, y = 12) {
print(x+y);
}

print(x+y);
```

The output from this program will be:

```27
5
```

The rules for the code block are the same as for any other code block in JavaScript. It may have its own local variables established using the `var` statement. As usual, you may not declare functions within a block.

Note: The parentheses following `let` are required. Failure to include them will result in a syntax error.

#### Scoping rules

The scope of variables defined using `let` is the `let` block itself, as well as any inner blocks contained inside it, unless those blocks define variables by the same names.

### `let` expressions

You can use `let` to establish variables that are scoped only to a single expression:

```var x = 5;
var y = 0;
print( let(x = x + 10, y = 12) x+y );
print(x+y);
```

The resulting output is:

```27
5
```

In this case, the binding of the values of x and y to `x+10` and `12` are scoped solely to the expression `x+y`.

#### Scoping rules

Given a `let` expression:

```let (decls) expr
```

There is an implicit block created around expr.

### `let` definitions

The `let` keyword can also be used to define variables, constants, and functions inside a block.

```if (x > y)
{
let const k = 37;
let gamma : int = 12.7 + k;
let i = 10;
let function f(n) { return (n/3)+k; }
return f(gamma) + f(i);
}
```

#### Scoping rules

Variables, functions, and constants declared by `let`, `let function`, and `let const` have as their scope the block in which they are defined, as well as in any sub-blocks in which they aren't redefined. In this way, `let` works very much like `var`.

In programs and classes `let` does not create properties on the global and class objects like `var` does; instead, it creates properties in an implicit block created for the evaluation of statements in those contexts. This essentially means that `let` won't override variables previously defined using `var`. For example:

```var x = 'global'
let x = 42
```

The alert displayed by this code will display "global", not " 42".

An implicit block is one that is not bracketed by braces; it's created implicitly by the JavaScript engine.

In functions, `let` executed by `eval()` does not create properties on the variable object (activation object or innermost binding rib) like `var` does; instead, it creates properties in an implicit block created for the evaluation of statements in the program. This is a consequence of `eval()` operating on programs in tandem with the previous rule.

In other words, when you use `eval()` to execute code, that code is treated as an independent program, which has its own implicit block around its code.

### `let`-scoped variables in `for` loops

You can use the `let` keyword to bind variables locally in the scope of `for` loops, just like you can with `var`.

```   var i=0;
for ( let i=i ; i < 10 ; i++ )
print(i);

for ( let &[name,value] in obj )
print("Name: " + name + ", Value: " + value);
```

#### Scoping rules

```for (let expr1; expr2; expr3) statement
```

In this example, expr2, expr3, and statement are enclosed in an implicit block that contains the block local variables declared by `let expr1`. This is demonstrated in the first loop above.

```for (expr1 in expr2) statement
```

In this case, there's an implicit block containing statement. This is shown in the second loop above.

## Destructuring assignment

Destructuring assignment makes it possible to extract data from arrays or objects using a syntax resembling array and object literals.

A key advantage to destructuring assignment is the ability for functions to return multiple values.

This section will be beefed up once I'm able to experiment.

This capability is similar to abilities present in languages such as Perl and Python.

### Multiple-value returns

Thanks to destructuring assignment, functions can return multiple values:

```function f() {
return [1, 2];
}

var a, b;
[a, b] = f();
```

After running this code, a is 1 and b is 2.

You can also ignore return values that you're not interested in:

```function f() {
return [1, 2, 3];
}

var [a, , b] = f();
```

After running this code, a is 1 and b is 3. The value 2 is ignored. You can ignore any (or all) returned values this way. For example:

```[,,,] = f();
```

### Looping across objects

You can also use destructuring assignment to pull data out of an object:

```for (let[name, value] in obj) {
print("Name: " + name + ", Value: " + value);
}
```

This pulls the name and value fields from the object obj and prints them.

### Looping across values in an object

You can loop across the values in an object as well:

```for each (let {name: n, family: { father: f } } in obj) {
print("Name: " + n + ", Father: " + f);
}
```

Add text explaining what this is doing.

## Row capture and record updating

Related to destructuring assignment, row capture lets you pull individual fields out of a structure, as well as a new structure that contains the fields you didn't explicitly extract.

For example:

```var personRecord = { name: "Bob", city: "Foohaven", job: "Programmer", employer: "Barco Inc." };

{ name: x, city: y, ...: z } = personRecord;
```

This code would extract the name and city fields into the variables x and y, respectively, and would also create a new structure, z, which is `{ job: "Programmer", employer: "Barco Inc." }`.

One valuable use for this capability is data preservation. If your code needs to be able to work with data that may contain fields you're not aware of, you can extract unknown fields into a structure to preserve them even though you don't know their names.

You can also combine values and structures together using this syntax. For example, if Bob moves, you need to change the city field in the record above. After that, you want to reconstruct the complete record again with the new data.

You can do this easily, like this:

```var newPersonRecord = { ... = z, city = "New Foohaven" };
```

After this, newPersonRecord contains `{ name: "Bob", city: "New Foohaven", job: "Programmer", employer: "Barco Inc." }`.

In simple terms, "`...`" is shorthand for "any fields I haven't expressly mentioned."