aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/web/javascript/reference/statements/let/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-tw/web/javascript/reference/statements/let/index.html')
-rw-r--r--files/zh-tw/web/javascript/reference/statements/let/index.html246
1 files changed, 246 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/statements/let/index.html b/files/zh-tw/web/javascript/reference/statements/let/index.html
new file mode 100644
index 0000000000..0cdc8806be
--- /dev/null
+++ b/files/zh-tw/web/javascript/reference/statements/let/index.html
@@ -0,0 +1,246 @@
+---
+title: let
+slug: Web/JavaScript/Reference/Statements/let
+translation_of: Web/JavaScript/Reference/Statements/let
+---
+<div>{{jsSidebar("Statements")}}</div>
+
+<p><strong><code>let</code></strong>用於宣告一個「只作用在當前區塊的變數」,初始值可選擇性的設定。</p>
+
+<div>{{EmbedInteractiveExample("pages/js/statement-let.html")}}</div>
+
+
+
+<h2 id="語法">語法</h2>
+
+<pre class="syntaxbox notranslate">let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];</pre>
+
+<h3 id="參數">參數</h3>
+
+<dl>
+ <dt><code>var1</code>, <code>var2</code>, …, <code>varN</code></dt>
+ <dd>變數名稱。</dd>
+ <dt><code>value1</code>, <code>value2</code>, …, <code>valueN</code></dt>
+ <dd>變數的初始值,可以是任何合法的表達式。</dd>
+</dl>
+
+<h2 id="描述">描述</h2>
+
+<p><code>let</code> 可以宣告只能在目前區塊、階段或表達式中作用的變數。而 <code><a href="https://developer.mozilla.org/zh-TW/docs/JavaScript/Reference/Statements/var" title="JavaScript/Reference/Statements/var">var</a> 則是定義了一個全域變數,或是在整個 function 而不管該區塊範圍。</code></p>
+
+<h3 id="Scoping_rules">Scoping rules</h3>
+
+<p>宣告 <code>let</code> 的作用範圍是它們被定義的區塊,以及該區塊包含的子區塊。這樣看起來功能跟 <strong><code>var</code></strong> 很相似。主要不同的地方在於 <strong><code>var</code></strong> 作用範圍是「整個」function:</p>
+
+<pre class="brush:js notranslate">function varTest() {
+ var x = 1;
+ {
+ var x = 2; // 這裡的 x 與 function 區塊內部的 x 是一樣的,因此會影響 function 區塊內所有的 x
+ console.log(x); // 2
+ }
+ console.log(x); // 2
+}
+
+function letTest() {
+ let x = 1;
+ {
+ let x = 2; // 這裡的 x 與 function 區塊內部的 x 是不同的,只會作用在這層 block 區塊中
+ console.log(x); // 2
+ }
+ console.log(x); // 1
+}</pre>
+
+<p>在上列例子裡的最前行 <code>let</code> 和 <code>var</code> 不同,<code>let</code> 並不會在全域物件中建立變數。舉例來說:</p>
+
+<pre class="brush:js notranslate">var x = 'global';
+let y = 'global';
+console.log(this.x); // "global"
+console.log(this.y); // undefined
+</pre>
+
+<h3 id="Emulating_private_members">Emulating private members</h3>
+
+<p>In dealing with <a href="/en-US/docs/Glossary/Constructor">constructors</a> it is possible to use the <strong><code>let</code></strong> bindings to share one or more private members without using <a href="/en-US/docs/Web/JavaScript/Closures">closures</a>:</p>
+
+<pre class="brush:js notranslate">var Thing;
+
+{
+ let privateScope = new WeakMap();
+ let counter = 0;
+
+ Thing = function() {
+ this.someProperty = 'foo';
+
+ privateScope.set(this, {
+ hidden: ++counter,
+ });
+ };
+
+ Thing.prototype.showPublic = function() {
+ return this.someProperty;
+ };
+
+ Thing.prototype.showPrivate = function() {
+ return privateScope.get(this).hidden;
+ };
+}
+
+console.log(typeof privateScope);
+// "undefined"
+
+var thing = new Thing();
+
+console.log(thing);
+// Thing {someProperty: "foo"}
+
+thing.showPublic();
+// "foo"
+
+thing.showPrivate();
+// 1
+</pre>
+
+<h3 id="Temporal_Dead_Zone_and_errors_with_let">Temporal Dead Zone and errors with <code>let</code></h3>
+
+<p>Redeclaring the same variable within the same function or block scope raises a {{jsxref("SyntaxError")}}.</p>
+
+<pre class="brush: js example-bad notranslate">if (x) {
+ let foo;
+ let foo; // SyntaxError thrown.
+}</pre>
+
+<p>In ECMAScript 2015, <strong><code>let</code></strong> bindings are not subject to <strong>Variable Hoisting</strong>, which means that <strong><code>let</code></strong> declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError">ReferenceError</a></code> (contrary to a variable declared with <a href="/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting">var</a>, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.</p>
+
+<pre class="brush: js notranslate">function do_something() {
+ console.log(foo); // ReferenceError
+ let foo = 2;
+}</pre>
+
+<p>你可能會在 <a href="https://developer.mozilla.org/zh-TW/docs/JavaScript/Reference/Statements/switch" title="switch"><code>switch</code></a> 中遇到錯誤,因為所有的 <code>case</code> 都屬於同樣的區塊中。</p>
+
+<pre class="brush: js notranslate">switch (x) {
+ case 0:
+ let foo;
+ break;
+
+ case 1:
+ let foo; // SyntaxError for redeclaration.
+ break;
+}</pre>
+
+<h3 id="let_於_for_迴圈的宣告範圍"><code>let</code> 於 <code>for</code> 迴圈的宣告範圍</h3>
+
+<p>You can use the <code>let</code> keyword to bind variables locally in the scope of <code>for</code> loops. This is different from the var keyword in the head of a for loop, which makes the variables visible in the whole function containing the loop.</p>
+
+<pre class="brush:js notranslate">var i=0;
+for ( let i=i ; i &lt; 10 ; i++ ) {
+ console.log(i);
+}
+</pre>
+
+<p>However, it's important to point out that a block nested inside a case clause will create a new block scoped lexical environment, which will not produce the redeclaration errors shown above.</p>
+
+<pre class="brush: js notranslate">let x = 1;
+
+switch(x) {
+ case 0: {
+ let foo;
+ break;
+ }
+ case 1: {
+ let foo;
+ break;
+ }
+}</pre>
+
+<h3 id="The_temporal_dead_zone_and_typeof">The temporal dead zone and <code>typeof</code></h3>
+
+<p>Unlike with simply undeclared variables and variables that hold a value of <code>undefined</code>, using the <code>typeof</code> operator to check for the type of a variable in that variable's TDZ will throw a <code>ReferenceError</code>:</p>
+
+<pre class="brush: js notranslate">// prints out 'undefined'
+console.log(typeof undeclaredVariable);
+// results in a 'ReferenceError'
+console.log(typeof i);
+let i = 10;</pre>
+
+<h3 id="Another_example_of_temporal_dead_zone_combined_with_lexical_scoping">Another example of temporal dead zone combined with lexical scoping</h3>
+
+<p>Due to lexical scoping, the identifier<strong> "foo"</strong> inside the expression <code>(foo + 55)</code> evaluates to the <u>if block's foo</u>, and <strong>not</strong> the <u>overlying variable foo</u> with the value of 33.<br>
+ In that very line, the <u>if block's "foo"</u> has already been created in the lexical environment, but has not yet reached (and <strong>terminated</strong>) its initialization (which is part of the statement itself): it's still in the temporal dead zone.</p>
+
+<pre class="brush: js example-bad notranslate">function test(){
+ var foo = 33;
+ {
+ let foo = (foo + 55); // ReferenceError
+ }
+}
+test();</pre>
+
+<p>This phenomenon may confuse you in a situation like the following. The instruction <code>let n of n.a</code> is already inside the private scope of the <u>for loop's block</u>, hence the identifier<strong> "n.a"</strong> is resolved to the property 'a' of the <u>'n' object located in the first part of the instruction itself</u> ("let n"), which is still in the temporal dead zone since its declaration statement has not been reached and <strong>terminated</strong>.</p>
+
+<pre class="brush: js example-bad notranslate">function go(n) {
+ // n here is defined!
+ console.log(n); // Object {a: [1,2,3]}
+
+ for (let n of n.a) { // ReferenceError
+ console.log(n);
+ }
+}
+
+go({a: [1, 2, 3]});
+</pre>
+
+<h2 id="Other_situations">Other situations</h2>
+
+<p>When used inside a block, <strong><code>let</code></strong> limits the variable's scope to that block. Note the difference between <code><strong>var</strong></code><em> </em>whose scope is inside the function where it is declared.</p>
+
+<pre class="brush: js notranslate">var a = 1;
+var b = 2;
+
+if (a === 1) {
+ var a = 11; // the scope is global
+ let b = 22; // the scope is inside the if-block
+
+ console.log(a); // 11
+ console.log(b); // 22
+}
+
+console.log(a); // 11
+console.log(b); // 2</pre>
+
+<h2 id="規範">規範</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ <th scope="col">Status</th>
+ <th scope="col">Comment</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES6', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td>
+ <td>{{Spec2('ES6')}}</td>
+ <td>Initial definition. Does not specify let expressions or let blocks.</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="瀏覽器相容性">瀏覽器相容性</h2>
+
+
+
+<p>{{Compat("javascript.statements.let")}}</p>
+
+<h2 id="參見">參見</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/var"><code>var</code></a></li>
+ <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/const"><code>const</code></a></li>
+ <li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/">ES6 In Depth: <code>let</code> and <code>const</code></a></li>
+ <li><a href="https://blog.mozilla.org/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/">Breaking changes in <code>let</code> and <code>const</code> in Firefox 44.</a></li>
+</ul>