JavaScript 1.7 新鮮事

  • 版本網址代稱: JavaScript_1.7_新鮮事
  • 版本標題: JavaScript 1.7 新鮮事
  • 版本 ID: 273349
  • 建立日期:
  • 建立者: Mgjbot
  • Is current revision?
  • 回應 robot Adding: [[en:New in JavaScript 1.7]], [[it:Novità in JavaScript 1.7]] <<langbot>>

版本內容

{{ 翻譯中("http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7") }}

JavaScript 1.7 是個程式語言上的更新,新推出了幾項新功能,諸如特定產生器 (generator)、迴圈器 (iterator)、陣列簡約式 (array comprehension)、let 表達式、以及跨結構指定 (destructuring assignment)。它也包含了所有 JavaScript 1.6 的功能。

Firefox 2 beta 1 起,以及目前的 Minefield 主幹 (trunk) 建造版,開始支援 JavaScript 1.7。

本文章使用的程式碼範例可以用 JavaScript shell 實驗。請參見 Introduction to the JavaScript shell 以得知如何建造及使用 shell。

使用 JavaScript 1.7

為了使用JavaScript 1.7的一些新功能,你必須載明你希望使用JavaScript 1.7。在HTML或XUL的原始碼中使用:

 <script type="application/javascript;version=1.7"/>

當使用JavaScript shell,而你必須設定想用的版本時,可以利用version()函式:

 version(170);

當碰到必須用到新關鍵字『yield』和『let』的情況時,你必須指定版本1.7,因為既有的程式可能會將那些關鍵字判讀為變數或函式的名字。當不需採用新關鍵字時(destructuring assignment and array comprehensions),可不必指定JavaScript的版本。

特定產生器 (generator) 與迴圈器 (iterator)

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.

特定產生器 (generator)

Consider this iterative algorithm that computes Fibonacci numbers:

function do_callback(num) {
  document.write(num + "<BR>\n");
}

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++) {
  document.write(g.next() + "<BR>\n");
}

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.

迴圈器 (iterator)

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

In normal usage, iterator objects are "invisible"; you won't need to operate on them explicitly, but will instead use JavaScript's for...in and for each...in statements to loop naturally over the keys and/or values of objects.

var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "<BR>\n");
}

If you are implementing your own iterator object, or have another need to directly manipulate iterators, you'll need to know about the next method, the StopIteration exception, and the __iterator__ property.

You can create an iterator for an object by calling Iterator(objectname); the iterator for an object is found via the object's __iterator__ property, which by default implements iteration according to the usual for...in and for each...in model. If you wish to provide a custom iterator, you should override the getter for __iterator__ to return an instance of your custom iterator. To get an object's iterator from script, you should use Iterator(obj) rather than accessing the __iterator__ property directly.

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.

Here's a simple example of direct iterator manipulation:

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

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "<BR>\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.<BR>\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "<BR>\n");
}

The output from this program looks like this:

name,Jack Bauer
username,JackB
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
username
id
agency
region
End of record.

In both cases, the actual order in which the data is returned may vary based on the implementation. There is no guaranteed ordering of the data.

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 comprehension)

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) 規則

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

Add details.

Block scope with let

有許多方式來使用let處理資料和函式的作用域:

  • let statement提供一種方式把值和作用域中的變數、常數和函式連繫起來,卻不影響在作用域外同名變數的值。
  • let expression讓你建立只對單一表達式有效的變數。
  • let definition定義的變數、常數和函式,其作用範圍受限於被定義的區塊。這個語法非常類似於var的用法。
  • 你也可以用let來建立在for迴圈中的變數。

let 表達式

The let statement provides local scoping for variables, constants, and functions. It works by binding zero or more variables in the lexical scope of 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) {
  document.write(x+y + "<BR>\n");
}

document.write(x+y + "<BR>\n");

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 let declarations.

Note: When using the let statement syntax, the parentheses following let are required. Failure to include them will result in a syntax error.

領域 (scoping) 規則

let所定義的變數其作用域即為let區塊本身,和其內部的區塊,除非內部區塊定義了相同名稱的變數。

let 表達式

你可以利用let來建立只對單一表達式有效的變數:

var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "<BR>\n");
document.write(x+y + "<BR>\n");

結果為:

27
5

在這個例子中,將x指定為x+10和將y指定為12只對x+y這個表達式有效。

領域 (scoping) 規則

假設有一個let表示式:

let (decls) expr

有個暗含的區塊包圍著expr

let 定義

let關鍵字也可以被用來定義在區塊中的變數、常數和函式。

Note: If you have more interesting examples of ways to use let definitions, please consider adding them here.
if (x > y)
{
   let gamma = 12.7 + y;
   i = gamma * x;
}

領域 (scoping) 規則

Variables declared by let 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 object 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:

** Doesn't work in FF 2.0 b1. Returns "42", not "global".
var x = 'global';
let x = 42;
document.write(this.x + "<BR>\n");

The output 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.

for 迴圈內的 let 領域變數

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

** Add obj **
   var i=0;
   for ( let i=i ; i < 10 ; i++ )
     document.write(i + "<BR>\n");

   for ( let [name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "<BR>\n");

領域 (scoping) 規則

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 (let expr1 in expr2) statement
for each(let expr1 in expr2) statement

In both these cases, there are implicit blocks containing each statement. The first of these is shown in the second loop above.

跨結構指定 (destructuring assignment)

Destructuring assignment makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.

The object and array literal expressions provide an easy way to create ad-hoc packages of data. Once you've created these packages of data, you can use them any way you want to. You can even return them from functions.

One particularly useful thing you can do with destructuring assignment is to read an entire structure in a single statement, although there are a number of interesting things you can do with them, as shown in the section full of examples that follows.

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

範例

Destructuring assignment is best explained through the use of examples, so here are a few for you to read over and learn from.

避免暫時變數

You can use destructuring assignment, for example, to swap values:

var a = 1;
var b = 3;

[a, b] = [b, a];

After executing this code, b is 1 and a is 3. Without destructuring assignment, swapping two values requires a temporary variable (or, in some low-level languages, the XOR-swap trick).

Similarly, it can be used to rotate three or more variables:

var a = 'o';
var b = "<font color = 'green'>o</font>";
var c = 'o';
var d = 'o';
var e = 'o';
var f = "<font color = 'blue'>o</font>";
var g = 'o';
var h = 'o';

for (lp=0;lp<40;lp++)
	{[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
	 document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"<br />");}

After executing this code, a visual colorful display of the variable rotation will be displayed.

Returning to our Fibonacci generator example from above, we can eliminate the temporary "t" variable by computing the new values of "i" and "j" in a single group-assignment statement:

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

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

傳回多數值

Thanks to destructuring assignment, functions can return multiple values. While it's always been possible to return an array from a function, this provides an added degree of flexibility.

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

As you can see, returning results is done using an array-like notation, with all the values to return enclosed in brackets. You can return any number of results in this way. In this example, f() returns the values {{ mediawiki.external('1, 2') }} as its output.

var a, b;
[a, b] = f();
document.write ("A is " + a + " B is " + b + "<BR>\n");

The command {{ mediawiki.external('a, b') }} = f() assigns the results of the function to the variables in brackets, in order: a is set to 1 and b is set to 2.

You can also retrieve the return values as an array:

var a = f();
document.write ("A is " + a);

In this case, a is an array containing the values 1 and 2.

在物件上迴圈

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

var obj = { width: 3, length: 1.5, color: "orange" };

for (let[name, value] in obj) {
  document.write ("Name: " + name + ", Value: " + value + "<BR>\n");
}

This loops over all the key/value pairs in the object obj and displays their names and values. In this case, the output looks like the following:

Name: width, Value: 3
Name: length, Value: 1.5
Name: color, Value: orange

在一陣列的物件上迴圈

You can loop over an array of objects, pulling out fields of interest from each object:

var people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith"
    },
    age: 35
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones"
    },
    age: 25
  }
];

for each (let {name: n, family: { father: f } } in people) {
  document.write ("Name: " + n + ", Father: " + f + "<BR>\n");
}

This pulls the name field into n and the family.father field into f, then prints them. This is done for each object in the people array. The output looks like this:

Name: Mike Smith, Father: Harry Smith
Name: Tom Jones, Father: Richard Jones

忽略一些傳回的數值

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

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

var [a, , b] = f();
document.write ("A is " + a + " B is " + b + "<BR>\n");

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();

Pulling values from a regular expression match

When the regular expression exec() method finds a match, it returns an array containing first the entire matched portion of the string and then the portions of the string that matched each parenthesized group in the regular expression. Destructuring assignment allows you to pull the parts out of this array easily, ignoring the full match if it is not needed.

// Simple regular expression to match http / https / ftp-style URLs.
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
if (!parsedURL)
  return null;
var [, protocol, fullhost, fullpath] = parsedURL;
{{ languages( { "en": "en/New_in_JavaScript_1.7", "es": "es/Novedades_en_JavaScript_1.7", "fr": "fr/Nouveaut\u00e9s_dans_JavaScript_1.7", "it": "it/Novit\u00e0_in_JavaScript_1.7", "ja": "ja/New_in_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}

版本來源

<p>{{ 翻譯中("http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7") }}
</p><p>JavaScript 1.7 是個程式語言上的更新,新推出了幾項新功能,諸如特定產生器 (generator)、迴圈器 (iterator)、陣列簡約式 (array comprehension)、<code>let</code> 表達式、以及跨結構指定 (destructuring assignment)。它也包含了所有 <a href="zh_tw/JavaScript_1.6_%e6%96%b0%e9%ae%ae%e4%ba%8b">JavaScript 1.6</a> 的功能。
</p><p>從 <a href="zh_tw/Firefox_2">Firefox 2</a> beta 1 起,以及目前的 Minefield 主幹 (trunk) 建造版,開始支援 JavaScript 1.7。
</p><p>本文章使用的程式碼範例可以用 JavaScript shell 實驗。請參見 <a href="zh_tw/Introduction_to_the_JavaScript_shell">Introduction to the JavaScript shell</a> 以得知如何建造及使用 shell。
</p>
<h2 name=".E4.BD.BF.E7.94.A8_JavaScript_1.7">使用 JavaScript 1.7</h2>
<p>為了使用JavaScript 1.7的一些新功能,你必須載明你希望使用JavaScript 1.7。在HTML或XUL的原始碼中使用:
</p>
<pre class="eval"> &lt;script type="application/javascript;version=1.7"/&gt;
</pre>
<p>當使用<a href="zh_tw/Introduction_to_the_JavaScript_shell">JavaScript shell</a>,而你必須設定想用的版本時,可以利用<code>version()</code>函式:
</p>
<pre class="eval"> version(170);
</pre>
<p>當碰到必須用到新關鍵字『yield』和『let』的情況時,你必須指定版本1.7,因為既有的程式可能會將那些關鍵字判讀為變數或函式的名字。當不需採用新關鍵字時(destructuring assignment and array comprehensions),可不必指定JavaScript的版本。
</p>
<h2 name=".E7.89.B9.E5.AE.9A.E7.94.A2.E7.94.9F.E5.99.A8_.28generator.29_.E8.88.87.E8.BF.B4.E5.9C.88.E5.99.A8_.28iterator.29">特定產生器 (generator) 與迴圈器 (iterator)</h2>
<p>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.
</p>
<h3 name=".E7.89.B9.E5.AE.9A.E7.94.A2.E7.94.9F.E5.99.A8_.28generator.29">特定產生器 (generator)</h3>
<p>Consider this iterative algorithm that computes Fibonacci numbers:
</p>
<pre>function do_callback(num) {
  document.write(num + "&lt;BR&gt;\n");
}

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

fib();
</pre>
<p>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.
</p><p>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:
</p>
<pre>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 &lt; 10; i++) {
  document.write(g.next() + "&lt;BR&gt;\n");
}
</pre>
<p>The function containing the <code>yield</code> 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 <code>next()</code> method performs another pass through the iterative algorithm. Each step's value is the value specified by the <code>yield</code> keyword. Think of <code>yield</code> as the generator-iterator version of <code>return</code>, indicating the boundary between each iteration of the algorithm. Each time you call <code>next()</code>, the generator code resumes from the statement following the <code>yield</code>.
</p><p>You cycle a generator-iterator by repeatedly calling its <code>next()</code> method until you reach your desired result condition. In this example, we can obtain however many Fibonacci numbers we want by continuing to call <code>g.next()</code> until we have the number of results we want.
</p>
<h3 name=".E8.BF.B4.E5.9C.88.E5.99.A8_.28iterator.29">迴圈器 (iterator)</h3>
<p>An <i>iterator</i> is a special object that lets you iterate over data.
</p><p>In normal usage, iterator objects are "invisible"; you won't need to operate on them explicitly, but will instead use JavaScript's <a href="zh_tw/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements"><code>for...in</code> and <code>for each...in</code> statements</a> to loop naturally over the keys and/or values of objects.
</p>
<pre>var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "&lt;BR&gt;\n");
}
</pre>
<p>If you are implementing your own iterator object, or have another need to directly manipulate iterators, you'll need to know about the <code>next</code> method, the <code>StopIteration</code> exception, and the <code>__iterator__</code> property.
</p><p>You can create an iterator for an object by calling <code>Iterator(<i>objectname</i>)</code>; the iterator for an object is found via the object's <code>__iterator__</code> property, which by default implements iteration according to the usual <code>for...in</code> and <code>for each...in</code> model. If you wish to provide a custom iterator, you should override the <a href="zh_tw/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters">getter</a> for <code>__iterator__</code> to return an instance of your custom iterator. To get an object's iterator from script, you should use <code>Iterator(<i>obj</i>)</code> rather than accessing the <code>__iterator__</code> property directly.
</p><p>Once you have an iterator, you can easily fetch the next item in the object by calling the iterator's <code>next()</code> method. If there is no data left, the <code>StopIteration</code> exception is thrown.
</p><p>Here's a simple example of direct iterator manipulation:
</p>
<pre>var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "&lt;BR&gt;\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.&lt;BR&gt;\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "&lt;BR&gt;\n");
}
</pre>
<p>The output from this program looks like this:
</p>
<pre>name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.
</pre>
<p>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 <code>next()</code> method. Changing <code>var it = Iterator(obj);</code> to <code>var it = Iterator(obj, true);</code> in the above sample results in the following output:
</p>
<pre>name
username
id
agency
region
End of record.
</pre>
<p>In both cases, the actual order in which the data is returned may vary based on the implementation. There is no guaranteed ordering of the data.
</p><p>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.
</p>
<h2 name=".E9.99.A3.E5.88.97.E7.B0.A1.E7.B4.84.E5.BC.8F_.28array_comprehension.29">陣列簡約式 (array comprehension)</h2>
<p>Array comprehensions are a use of generators that provides a convenient way to perform powerful initialization of arrays. For example:
</p>
<pre class="eval">function range(begin, end) {
  for (let i = begin; i &lt; end; ++i) {
    yield i;
  }
}
</pre>
<p><code>range()</code> 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:
</p>
<pre class="eval">var ten_squares = [i * i for (i in range(0, 10))];
</pre>
<p>This pre-initializes a new array, <var>ten_squares</var>, to contain the squares of the values in the range <code>0..9</code>.
</p><p>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:
</p>
<pre class="eval">var evens = [i for (i in range(0, 21)) if (i % 2 == 0)];
</pre>
<p>Prior to JavaScript 1.7, this would have to be coded something like this:
</p>
<pre>var evens = [];
for (var i=0; i &lt;= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}
</pre>
<p>Not only is the array comprehension much more compact, but it's actually easier to read, once you're familiar with the concept.
</p>
<h4 name=".E9.A0.98.E5.9F.9F_.28scoping.29_.E8.A6.8F.E5.89.87">領域 (scoping) 規則</h4>
<p>Array comprehensions have an implicit block around them, containing everything inside the square brackets, as well as implicit <code>let</code> declarations.
</p><p><i>Add details.</i>
</p>
<h2 name="Block_scope_with_let">Block scope with <code>let</code></h2>
<p>有許多方式來使用<code>let</code>處理資料和函式的作用域:
</p>
<ul><li> <b><code>let</code> statement</b>提供一種方式把值和作用域中的變數、常數和函式連繫起來,卻不影響在作用域外同名變數的值。
</li><li> <b><code>let</code> expression</b>讓你建立只對單一表達式有效的變數。
</li><li> <b><code>let</code> definition</b>定義的變數、常數和函式,其作用範圍受限於被定義的區塊。這個語法非常類似於<code>var</code>的用法。
</li><li> 你也可以用<code>let</code>來建立在<code>for</code>迴圈中的變數。
</li></ul>
<h3 name="let_.E8.A1.A8.E9.81.94.E5.BC.8F"><code>let</code> 表達式</h3>
<p>The <code>let</code> statement provides local scoping for variables, constants, and functions. It works by binding zero or more variables in the lexical scope of a single block of code. The completion value of the <code>let</code> statement is the completion value of the block.
</p><p>For example:
</p>
<pre>var x = 5;
var y = 0;

let (x = x+10, y = 12) {
  document.write(x+y + "&lt;BR&gt;\n");
}

document.write(x+y + "&lt;BR&gt;\n");
</pre>
<p>The output from this program will be:
</p>
<pre>27
5
</pre>
<p>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 <code>let</code> declarations.
</p>
<div class="note"><b>Note:</b> When using the <code>let</code> statement syntax, the parentheses following <code>let</code> are required. Failure to include them will result in a syntax error.</div>
<h4 name=".E9.A0.98.E5.9F.9F_.28scoping.29_.E8.A6.8F.E5.89.87_2">領域 (scoping) 規則</h4>
<p>用<code>let</code>所定義的變數其作用域即為<code>let</code>區塊本身,和其內部的區塊,除非內部區塊定義了相同名稱的變數。
</p>
<h3 name="let_.E8.A1.A8.E9.81.94.E5.BC.8F_2"><code>let</code> 表達式</h3>
<p>你可以利用<code>let</code>來建立只對單一表達式有效的變數:
</p>
<pre>var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "&lt;BR&gt;\n");
document.write(x+y + "&lt;BR&gt;\n");
</pre>
<p>結果為:
</p>
<pre>27
5
</pre>
<p>在這個例子中,將<var>x</var>指定為<code>x+10</code>和將<var>y</var>指定為<code>12</code>只對<code>x+y</code>這個表達式有效。
</p>
<h4 name=".E9.A0.98.E5.9F.9F_.28scoping.29_.E8.A6.8F.E5.89.87_3">領域 (scoping) 規則</h4>
<p>假設有一個<code>let</code>表示式:
</p>
<pre class="eval">let (<var>decls</var>) <var style="color: blue">expr</var>
</pre>
<p>有個暗含的區塊包圍著<var style="color: blue">expr</var>。
</p>
<h3 name="let_.E5.AE.9A.E7.BE.A9"><code>let</code> 定義</h3>
<p><code>let</code>關鍵字也可以被用來定義在區塊中的變數、常數和函式。
</p>
<div class="note"><b>Note:</b> If you have more interesting examples of ways to use <code>let</code> definitions, please consider adding them here.</div>
<pre>if (x &gt; y)
{
   let gamma = 12.7 + y;
   i = gamma * x;
}
</pre>
<h4 name=".E9.A0.98.E5.9F.9F_.28scoping.29_.E8.A6.8F.E5.89.87_4">領域 (scoping) 規則</h4>
<p>Variables declared by <code>let</code> 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, <code>let</code> works very much like <code>var</code>.
</p><p>In programs and classes <code>let</code> does not create properties on the global object like <code>var</code> does; instead, it creates properties in an implicit block created for the evaluation of statements in those contexts. This essentially means that <code>let</code> won't override variables previously defined using <code>var</code>. For example:
</p>
<pre>** Doesn't work in FF 2.0 b1. Returns "42", not "global".
var x = 'global';
let x = 42;
document.write(this.x + "&lt;BR&gt;\n");
</pre>
<p>The output displayed by this code will display "global", not " 42".
</p><p>An <i>implicit block</i> is one that is not bracketed by braces; it's created implicitly by the JavaScript engine.
</p><p>In functions, <code>let</code> executed by <code>eval()</code> does not create properties on the variable object (activation object or innermost binding rib) like <code>var</code> does; instead, it creates properties in an implicit block created for the evaluation of statements in the program. This is a consequence of <code>eval()</code> operating on programs in tandem with the previous rule.
</p><p>In other words, when you use <code>eval()</code> to execute code, that code is treated as an independent program, which has its own implicit block around its code.
</p>
<h3 name="for_.E8.BF.B4.E5.9C.88.E5.85.A7.E7.9A.84_let_.E9.A0.98.E5.9F.9F.E8.AE.8A.E6.95.B8"><code>for</code> 迴圈內的 <code>let</code> 領域變數</h3>
<p>You can use the <code>let</code> keyword to bind variables locally in the scope of <code>for</code> loops, just like you can with <code>var</code>.
</p>
<pre>** Add obj **
   var i=0;
   for ( let i=i ; i &lt; 10 ; i++ )
     document.write(i + "&lt;BR&gt;\n");

   for ( let [name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "&lt;BR&gt;\n");
</pre>
<h4 name=".E9.A0.98.E5.9F.9F_.28scoping.29_.E8.A6.8F.E5.89.87_5">領域 (scoping) 規則</h4>
<pre class="eval">for (let <var>expr1</var>; <var style="color: blue">expr2</var>; <var style="color: blue">expr3</var>) <var style="color: blue">statement</var>
</pre>
<p>In this example, <var style="color: blue">expr2</var>, <var style="color: blue">expr3</var>, and <var style="color: blue">statement</var> are enclosed in an implicit block that contains the block local variables declared by <code>let <var>expr1</var></code>. This is demonstrated in the first loop above.
</p>
<pre class="eval">for (let <var>expr1</var> in <var>expr2</var>) <var style="color: blue">statement</var>
for each(let <var>expr1</var> in <var>expr2</var>) <var style="color: blue">statement</var>
</pre>
<p>In both these cases, there are implicit blocks containing each <var style="color: blue">statement</var>. The first of these is shown in the second loop above.
</p>
<h2 name=".E8.B7.A8.E7.B5.90.E6.A7.8B.E6.8C.87.E5.AE.9A_.28destructuring_assignment.29">跨結構指定 (destructuring assignment)</h2>
<p>Destructuring assignment makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.
</p><p>The object and array literal expressions provide an easy way to create ad-hoc packages of data. Once you've created these packages of data, you can use them any way you want to. You can even return them from functions.
</p><p>One particularly useful thing you can do with destructuring assignment is to read an entire structure in a single statement, although there are a number of interesting things you can do with them, as shown in the section full of examples that follows.
</p><p>This capability is similar to features present in languages such as Perl and Python.
</p>
<h3 name=".E7.AF.84.E4.BE.8B">範例</h3>
<p>Destructuring assignment is best explained through the use of examples, so here are a few for you to read over and learn from.
</p>
<h4 name=".E9.81.BF.E5.85.8D.E6.9A.AB.E6.99.82.E8.AE.8A.E6.95.B8">避免暫時變數</h4>
<p>You can use destructuring assignment, for example, to swap values:
</p>
<pre>var a = 1;
var b = 3;

[a, b] = [b, a];
</pre>
<p>After executing this code, <var>b</var> is 1 and <var>a</var> is 3. Without destructuring assignment, swapping two values requires a temporary variable (or, in some low-level languages, the <a class="external" href="http://en.wikipedia.org/wiki/XOR_swap">XOR-swap trick</a>).
</p><p>Similarly, it can be used to rotate three or more variables:
</p>
<pre>var a = 'o';
var b = "&lt;font color = 'green'&gt;o&lt;/font&gt;";
var c = 'o';
var d = 'o';
var e = 'o';
var f = "&lt;font color = 'blue'&gt;o&lt;/font&gt;";
var g = 'o';
var h = 'o';

for (lp=0;lp&lt;40;lp++)
	{[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
	 document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"&lt;br /&gt;");}
</pre>
<p>After executing this code, a visual colorful display of the variable rotation will be displayed.
</p><p>Returning to our Fibonacci generator example from above, we can eliminate the temporary "t" variable by computing the new values of "i" and "j" in a single group-assignment statement:
</p>
<pre>function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    [i, j] = [j, i + j];
  }
}

var g = fib();
for (let i = 0; i &lt; 10; i++)
  print(g.next());
</pre>
<h4 name=".E5.82.B3.E5.9B.9E.E5.A4.9A.E6.95.B8.E5.80.BC">傳回多數值</h4>
<p>Thanks to destructuring assignment, functions can return multiple values. While it's always been possible to return an array from a function, this provides an added degree of flexibility.
</p>
<pre>function f() {
  return [1, 2];
}
</pre>
<p>As you can see, returning results is done using an array-like notation, with all the values to return enclosed in brackets. You can return any number of results in this way. In this example, <code>f()</code> returns the values <code>{{ mediawiki.external('1, 2') }}</code> as its output.
</p>
<pre>var a, b;
[a, b] = f();
document.write ("A is " + a + " B is " + b + "&lt;BR&gt;\n");
</pre>
<p>The command <code>{{ mediawiki.external('a, b') }} = f()</code> assigns the results of the function to the variables in brackets, in order: <var>a</var> is set to 1 and <var>b</var> is set to 2.
</p><p>You can also retrieve the return values as an array:
</p>
<pre>var a = f();
document.write ("A is " + a);
</pre>
<p>In this case, <var>a</var> is an array containing the values 1 and 2.
</p>
<h4 name=".E5.9C.A8.E7.89.A9.E4.BB.B6.E4.B8.8A.E8.BF.B4.E5.9C.88">在物件上迴圈</h4>
<p>You can also use destructuring assignment to pull data out of an object:
</p>
<pre>var obj = { width: 3, length: 1.5, color: "orange" };

for (let[name, value] in obj) {
  document.write ("Name: " + name + ", Value: " + value + "&lt;BR&gt;\n");
}
</pre>
<p>This loops over all the key/value pairs in the object <var>obj</var> and displays their names and values. In this case, the output looks like the following:
</p>
<pre>Name: width, Value: 3
Name: length, Value: 1.5
Name: color, Value: orange
</pre>
<h4 name=".E5.9C.A8.E4.B8.80.E9.99.A3.E5.88.97.E7.9A.84.E7.89.A9.E4.BB.B6.E4.B8.8A.E8.BF.B4.E5.9C.88">在一陣列的物件上迴圈</h4>
<p>You can loop over an array of objects, pulling out fields of interest from each object:
</p>
<pre>var people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith"
    },
    age: 35
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones"
    },
    age: 25
  }
];

for each (let {name: n, family: { father: f } } in people) {
  document.write ("Name: " + n + ", Father: " + f + "&lt;BR&gt;\n");
}
</pre>
<p>This pulls the <var>name</var> field into <var>n</var> and the <var>family.father</var> field into <var>f</var>, then prints them. This is done for each object in the <var>people</var> array. The output looks like this:
</p>
<pre>Name: Mike Smith, Father: Harry Smith
Name: Tom Jones, Father: Richard Jones
</pre>
<h4 name=".E5.BF.BD.E7.95.A5.E4.B8.80.E4.BA.9B.E5.82.B3.E5.9B.9E.E7.9A.84.E6.95.B8.E5.80.BC">忽略一些傳回的數值</h4>
<p>You can also ignore return values that you're not interested in:
</p>
<pre>function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
document.write ("A is " + a + " B is " + b + "&lt;BR&gt;\n");
</pre>
<p>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:
</p>
<pre>[,,,] = f();
</pre>
<h4 name="Pulling_values_from_a_regular_expression_match">Pulling values from a regular expression match</h4>
<p>When the regular expression <code><a href="zh_tw/Core_JavaScript_1.5_Reference/Global_Objects/RegExp/exec">
exec()</a></code> method finds a match, it returns an array containing first the entire matched portion of the string and then the portions of the string that matched each parenthesized group in the regular expression. Destructuring assignment allows you to pull the parts out of this array easily, ignoring the full match if it is not needed.
</p>
<pre>// Simple regular expression to match http / https / ftp-style URLs.
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
if (!parsedURL)
  return null;
var [, protocol, fullhost, fullpath] = parsedURL;
</pre>
<div class="noinclude">
</div>
{{ languages( { "en": "en/New_in_JavaScript_1.7", "es": "es/Novedades_en_JavaScript_1.7", "fr": "fr/Nouveaut\u00e9s_dans_JavaScript_1.7", "it": "it/Novit\u00e0_in_JavaScript_1.7", "ja": "ja/New_in_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}
Revert to this revision