diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
commit | 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 (patch) | |
tree | a9ef8ac1e1b8fe4207b6d64d3841bfb8990b6fd0 /files/zh-tw/web/javascript/guide | |
parent | 074785cea106179cb3305637055ab0a009ca74f2 (diff) | |
download | translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.gz translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.bz2 translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.zip |
initial commit
Diffstat (limited to 'files/zh-tw/web/javascript/guide')
15 files changed, 6492 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/guide/control_flow_and_error_handling/index.html b/files/zh-tw/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..fd658f1c77 --- /dev/null +++ b/files/zh-tw/web/javascript/guide/control_flow_and_error_handling/index.html @@ -0,0 +1,429 @@ +--- +title: 流程控制與例外處理 +slug: Web/JavaScript/Guide/Control_flow_and_error_handling +tags: + - Beginner + - Guide + - JavaScript + - 初學者 + - 指南 +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> + +<p class="summary">JavaScript 擁有許多陳述式,特別是流程控制的陳述式,你可以用這些陳述式來增加程式的互動性。這個章節將會概要介紹陳述式。</p> + +<p><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements">JavaScript 參考</a>中有比本章更多關於陳述式的細節。 在 Javascript 程式碼中,分號(;)被用來隔開陳述式。</p> + +<p>任何 JavaScript 運算式也是一個陳述式。 有關運算式的完整資訊,請參閱<a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators">運算式與運算子</a>。</p> + +<h2 id="區塊陳述式">區塊陳述式</h2> + +<p>最基本的陳述式是「用於將陳述式分塊」的「區塊陳述式」。程式區塊被以一對大括號隔離開來:</p> + +<pre class="syntaxbox">{ + 陳述式 1; + 陳述式 2; + . + . + . + 陳述式 n; +} +</pre> + +<h3 id="範例"><strong>範例</strong></h3> + +<p>區塊陳述式經常與流程控制陳述式(例如:<code>if</code>、<code>for</code>、<code>while</code>)搭配使用。</p> + +<pre class="brush: js">while (x < 10) { + x++; +} +</pre> + +<p>在這裏,<code>{ x++; }</code> 是區塊陳述式。</p> + +<p><strong>重要</strong>:JavaScript 在 ECMAScript2015 (第六版)以前的版本並<strong>沒有</strong>區塊範圍的概念。 在區塊中的變數有效範圍是包含該區塊的函式或者是執行檔,並且在區塊外也可使用它們。換句話說,區塊並不定義了範圍。JavaScript 中的"獨立"區塊將會產生與 C 和 Java 中不同的效果。舉例來說:</p> + +<pre class="brush: js">var x = 1; +{ + var x = 2; +} +console.log(x); // 輸出 2 +</pre> + +<p>這裏輸出了 2 是因為區塊中變數 <code>var x</code> 陳述式擁有與區塊外的 <code>var x</code> 相同的有效範圍。在 C 或 Java,相同的程式碼將會輸出 1。</p> + +<p>從 ECMAScript2015 版本起, 使用 <code>let</code> 定義的變數範圍將被限制於區塊內。</p> + +<h2 id="條件陳述式">條件陳述式</h2> + +<p>條件陳述式是一些在指定條件爲真下將被執行的指令。 JavaScript 支援兩種條件陳述式: <code>if...else</code> 和 <code>switch</code>。</p> + +<h3 id="if...else_陳述式"><code>if...else</code> 陳述式</h3> + +<p><code>if 陳述式將在「邏輯判斷爲真」下執行接下來的一個陳述式</code>。選擇性的 <code>else</code> 陳述式將會在「邏輯判斷爲否」時被執行。 <code>if</code> 陳述式的用法看起來如下:</p> + +<pre class="syntaxbox">if (指定條件) { + 陳述式 1; +} else { + 陳述式 2; +}</pre> + +<p>指定條件可以是任何會回傳true或false的運算式。參見 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Boolean#Description">Boolean</a> 來進一步瞭解哪些運算式會回傳 <code>true</code> 及 <code>false</code>。假如指定條件爲 <code>true</code>,陳述式 1 會被執行;否則,陳述式 2 會被執行。陳述式 1 及陳述式 2 可以是任何陳述式,包含巢狀 <code>if</code> 陳述式。</p> + +<p>你也可以藉由 <code>else if</code> 來使用複合的陳述式來測試多種不同的條件,如下:</p> + +<pre class="syntaxbox">if (指定條件1) { + 陳述式 1; +} else if (指定條件 2) { + 陳述式 2; +} else if (指定條件 n) { + 陳述式 n; +} else { + 最後陳述式; +} +</pre> + +<p>在多個條件中,只有第一個條件爲 true 的陳述式會被執行。若要執行多個陳述式,可以將陳述式包在同一個程式區塊中(<code>{ ... }</code>)。 通常來說,使用區塊陳述式是很好的習慣,尤其在使用巢狀 if 的時候:</p> + +<pre class="syntaxbox">if (指定條件) { + 陳述式_1_執行_當_指定條件_爲_真; + 陳述式_2_執行_當_指定條件_爲_真; +} else { + 陳述式_3_執行_當_指定條件_爲_否; + 陳述式_4_執行_當_指定條件_爲_否; +} +</pre> + +<div>建議不要在以賦值作爲條件運算式,因為"賦值"常常被和"等於"搞混。 例如, 不要寫出如下面的程式碼:</div> + +<pre class="example-bad brush: js">if (x = y) { + /* 陳述式 */ +} +</pre> + +<p>如果你真的需要以賦值作爲條件運算式,一種常見的方式是額外在賦值式外面加上一組括號。例如:</p> + +<pre class="brush: js">if ((x = y)) { + /* 陳述式 */ +} +</pre> + +<h4 id="爲否的值">爲"否"的值</h4> + +<p>下列的值會被看作 false(也稱為 {{Glossary("Falsy")}} 值)</p> + +<ul> + <li><code>false</code></li> + <li><code>undefined</code></li> + <li><code>null</code></li> + <li><code>0</code></li> + <li><code>NaN</code></li> + <li>空字串(<code>""</code>)</li> +</ul> + +<p>其他所有的值,包含所有物件,當被作為條件陳述式都會被視為 <code>true</code>。</p> + +<p>不要把"布林真假值"和"布林物件的真假值"弄混了。 例如:</p> + +<pre class="brush: js">var b = new Boolean(false); +if (b) // 這會是 True +if (b == true) // 這會是 false +</pre> + +<h4 id="範例_2"><strong>範例</strong></h4> + +<p>在下面的範例中,函式 <code>checkData</code> 回傳 <code>true</code> 當 <code>Text</code> 物件的長度爲三;否則, 顯示出 alert 並回傳 <code>false</code>。</p> + +<pre class="brush: js">function checkData() { + if (document.form1.threeChar.value.length == 3) { + return true; + } else { + alert("請輸入恰好三個字元. " + + document.form1.threeChar.value + " is not valid."); + return false; + } +} +</pre> + +<h3 id="switch_陳述式"><code>switch</code> 陳述式</h3> + +<p><code>switch</code> 陳述式允許程式依運算式的不同值來選擇不同標籤。 假如運算式和標籤匹配,程式會執行標籤對應的陳述式。範例如下:</p> + +<pre class="syntaxbox">switch (運算式) { + case 標籤 1: + 陳述式 1 + [break;] + case 標籤 2: + 陳述式 2 + [break;] + ... + default: + 陳述式 + [break;] +} +</pre> + +<p>程序首先尋找一個標籤與運算式的值匹配的 <code>case</code> 子句,然後將控制權轉移給該子句,執行與其相關的陳述式。 如果沒有找到匹配的標籤,程序將查找 <code>default</code> 子句(選擇性),如果找到,則將控制權轉移到該子句,執行關聯的陳述式。 如果沒有找到 <code>default</code> 子句,程序繼續在 <code>switch</code> 結束後的陳述式執行。 按照慣例,默認子句是最後一個子句,但並不硬性規定。</p> + +<p>與每個 <code>case</code> 子句相關聯的 <code>break</code> 陳述式(選擇性)確保程序在發現匹配的陳述式之後退出 <code>switch</code>,並在 <code>switch</code> 後的陳述式中繼續執行。 如果省略 <code>break</code>,程序將繼續在 <code>switch</code> 陳述式中的下一個陳述式執行。</p> + +<h4 id="範例_3"><strong>範例</strong></h4> + +<p>在下面範例中,如果變數 <code>fruittype</code> 為「Bananas」,程序將與「Bananas」匹配並執行相關陳述式。 當遇到 <code>break</code> 時,程序離開 <code>switch</code> 並執行 <code>switch</code> 後的陳述式。 如果省略 <code>break</code>,也將執行 case 「Cherries」的陳述式。</p> + +<pre class="brush: js">switch (fruittype) { + case "Oranges": + console.log("Oranges are $0.59 a pound."); + break; + case "Apples": + console.log("Apples are $0.32 a pound."); + break; + case "Bananas": + console.log("Bananas are $0.48 a pound."); + break; + case "Cherries": + console.log("Cherries are $3.00 a pound."); + break; + case "Mangoes": + console.log("Mangoes are $0.56 a pound."); + break; + case "Papayas": + console.log("Mangoes and papayas are $2.79 a pound."); + break; + default: + console.log("Sorry, we are out of " + fruittype + "."); +} +console.log("Is there anything else you'd like?");</pre> + +<h2 id="例外處理陳述式">例外處理陳述式</h2> + +<p>你可以用以 <code>throw</code> 陳述式丟出例外,並以 <code>try...catch</code> 陳述式處理之。</p> + +<ul> + <li><a href="#throw_statement"><code>throw</code> 陳述式</a></li> + <li><a href="#try...catch_statement"><code>try...catch</code> 陳述式</a></li> +</ul> + +<h3 id="例外的形態">例外的形態</h3> + +<p>任何物件(object)都可以在 JavaScript 中被拋出。 然而,並非所有拋出的物件都相同。 雖然將數字或字串作為錯誤物件使用是相當常見的,但使用為此目的專門創造的一種例外物件類型通常更有效:</p> + +<ul> + <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects#Fundamental_objects">ECMAScript 例外</a></li> + <li>{{domxref("DOMException")}} and {{domxref("DOMError")}}</li> +</ul> + +<h3 id="throw_陳述式"><code>throw</code> 陳述式</h3> + +<p>使用 <code>throw</code> 陳述式拋出例外。當拋出例外時,你要指定包含在要拋出物件中的值:</p> + +<pre class="syntaxbox">throw expression; +</pre> + +<p>您可以拋出任何運算式,而不僅僅是特定類型的運算式。以下的程式碼會拋出一些不同類型的例外:</p> + +<pre class="brush: js">throw "Error2"; // 字串形態 +throw 42; // 數字形態 +throw true; // True/False +throw {toString: function() { return "我是物件!"; } }; +</pre> + +<div class="note"><strong>備註:</strong>您可以在拋出例外時指定物件。 然後,可以在 catch 區塊中引用對象的屬性。</div> + +<pre class="brush: js">// 創建類型爲 UserException 的物件 +function UserException(message) { + this.message = message; + this.name = "UserException"; +} + +// 讓例外轉換成整齊的字串當它被當作字串使用時 +// (舉例來說:於 error console) +UserException.prototype.toString = function() { + return this.name + ': "' + this.message + '"'; +} + +// 創建一個物件的實例並丟出它 +throw new UserException("Value too high");</pre> + +<h3 id="try...catch_陳述式"><code>try...catch</code> 陳述式</h3> + +<p><code>try...catch</code> 陳述式標記了一組要嘗試的陳述式,並在拋出例外時指定一個或多個響應。 如果例外被拋出,<code>try...catch</code> 陳述式捕獲它。</p> + +<p><code>try...catch</code> 陳述式包括一個 <code>try</code> 區塊,它包含一個或多個陳述式,零個或多個 <code>catch</code> 區塊,包含在 <code>try</code> 區塊中拋出例外時該做什麼的陳述式。 也就是說,你希望 <code>try</code> 區塊成功,如果它不成功,你希望控制權傳遞給 <code>catch</code> 區塊。 如果 <code>try</code> 區塊內的任何陳述式(或在 <code>try</code> 區塊內調用的函數中)拋出例外,則控制立即切換到 <code>catch</code> 區塊。 如果在 <code>try</code> 區塊中沒有拋出例外,則跳過 <code>catch</code> 區塊。 <code>finally</code> 區塊在 <code>try</code> 和 <code>catch</code> 區塊執行後執行,但在 <code>try...catch</code> 陳述式之後的陳述式之前執行。</p> + +<p>以下的範例使用 <code>try...catch</code> 陳述式。該範例調用基於傳遞給函數的值並從陣列中檢索月份名稱的函數。如果值不對應於月份數(1-12),則會拋出一個例外,其值為 "InvalidMonthNo",並且 <code>catch</code> 區塊中的陳述式將 <code>monthName</code> 變數設置為 <code>unknown</code>。</p> + +<pre class="brush: js">function getMonthName(mo) { + mo = mo - 1; // Adjust month number for array index (1 = Jan, 12 = Dec) + var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul", + "Aug","Sep","Oct","Nov","Dec"]; + if (months[mo]) { + return months[mo]; + } else { + throw "InvalidMonthNo"; //throw 關鍵字在這裏被使用 + } +} + +try { // statements to try + monthName = getMonthName(myMonth); // 函式可以丟出例外 +} +catch (e) { + monthName = "unknown"; + logMyErrors(e); // 將例外傳至例外處理機制 +} +</pre> + +<h4 id="The_catch_Block" name="The_catch_Block"><code>catch</code> 區塊</h4> + +<p>你可以使用 <code>catch</code> 區塊來處理 <code>try</code> 區塊可能丟出的例外。</p> + +<pre class="syntaxbox">catch (catchID) { + 陳述式 +} +</pre> + +<p><code>catch</code> 區塊指定用來保存 <code>throw</code> 陳述式所丟出的值的標識符(前面語法中的 <code>catchID</code>) 您可以使用此標識符獲取有關被拋出的例外的信息。 JavaScript 在進入<code>catch</code> 區塊時創建此標識符; 標識符僅持續 <code>catch</code> 區塊的持續時間;在 <code>catch</code> 區塊完成執行後,標識符不再可用。</p> + +<p>例如,下列的程式碼中丟出了一個例外,當例外發生後,控制權被轉交給 <code>catch</code> 區塊。</p> + +<pre class="brush: js">try { + throw "myException"; // 產生例外 +} +catch (e) { + // 用於處理例外的陳述式 + logMyErrors(e); // 將例外物件傳給 error handler +} +</pre> + +<h4 id="finally_區塊"><code>finally</code> 區塊</h4> + +<p><code>finally</code> 區塊中包含在 <code>try</code> 和 <code>catch</code> 區塊執行之後但在 <code>try...catch</code> 陳述式之後的陳述式之前 執行的陳述式。 無論是否拋出例外,<code>finally</code> 區塊都會執行。 如果拋出例外,則即使沒有 <code>catch</code> 區塊處理例外,<code>finally</code> 區塊中的陳述式也會執行。</p> + +<p>您可以使用 <code>finally</code> 區塊來使腳本在發生例外時正常地結束。例如,您可能需要釋放腳本中綁定的資源。 在以下示例中,打開一個文件,然後執行使用該文件的陳述式(伺服器端 JavaScript 允許您訪問文件)。 如果在打開文件時拋出例外,<code>finally</code> 區塊會在腳本結束之前關閉文件。</p> + +<pre class="brush: js">openMyFile(); +try { + writeMyFile(theData); // 可能產生例外 +} catch(e) { + handleError(e); // 處理可能發生的例外 +} finally { + closeMyFile(); // 總是在 try 結束後關閉檔案 +} +</pre> + +<p>如果 <code>finally</code> 區塊有返回值,那麼該值將成為整個 <code>try-catch-finally</code> 過程的返回值,而捨棄 <code>try</code> 和 <code>catch</code> 區塊中的任何返回陳述式:</p> + +<pre class="brush: js">function f() { + try { + console.log(0); + throw "bogus"; + } catch(e) { + console.log(1); + return true; // 這個回傳會被擱置 + // 直到 finally 區塊結束 + console.log(2); // 不會到達這裏 + } finally { + console.log(3); + return false; // 覆寫先前的 "return" + console.log(4); // 不會到達這裏 + } + // "return false" 在這裏被執行 + console.log(5); // 不會到達這裏 +} +f(); // console 0, 1, 3; 會回傳false +</pre> + +<p><code>finally</code> 區塊覆寫返回值也適用於在 <code>catch</code> 區塊中拋出或重新拋出的例外(即便在<code>catch</code> 中再次丟出例外,<code>catch</code> 所屬的 <code>finally</code> 區塊還是會被執行):</p> + +<pre class="brush: js">function f() { + try { + throw "bogus"; + } catch(e) { + console.log('caught inner "bogus"'); + throw e; // 此處的 throw 陳述式將被擱置到 + // finally區塊結束 + } finally { + return false; // 覆寫先前的"throw" + } + // "return false" 在此被執行 +} + +try { + f(); +} catch(e) { + // 這裏永遠不可能到達因為在f函式中catch的throw + // 被finally中的return覆寫了 + console.log('caught outer "bogus"'); +} + +// 輸出 -> caught inner "bogus"</pre> + +<h4 id="Nesting_try...catch_Statements" name="Nesting_try...catch_Statements">巢狀 try...catch 陳述式</h4> + +<p>你可以使用一個或多個的 <code>try...catch</code> 陳述式。 假如一個內層的<code>try...catch</code> 陳述式不具有 <code>catch</code> 區塊, 它將必須要有 <code>finally</code> 區塊與及封閉的 <code>try...catch</code> 陳述式來檢測是否有符合的例外。</p> + +<h3 id="使用_Error_物件">使用 <code>Error</code> 物件</h3> + +<p>根據錯誤的類型,您可以使用 "name" 和 "message" 屬性來獲取更精確的資訊。"name" 提供了錯誤所屬的類別(class)(例如,"DOMException" 或 "Error"),而 "message" 通常提供藉由將錯誤物件轉換為字串所獲得的更簡潔的資訊。參見<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#Nested_try-blocks">巢狀 try 區塊</a>位於 <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 參考資料頁面。</p> + +<p>假如您要丟出自定義的例外, 為了方便使用這些屬性(例如,如果你的 <code>catch</code> 區塊並不要區分你自己的例外和系統的),你可以使用 <code>Error</code> 構造子。舉例來說:</p> + +<pre class="brush: js">function doSomethingErrorProne () { + if (ourCodeMakesAMistake()) { + throw (new Error('The message')); + } else { + doSomethingToGetAJavascriptError(); + } +} +.... +try { + doSomethingErrorProne(); +} +catch (e) { + console.log(e.name); // 紀錄 'Error' + console.log(e.message); // 紀錄 'The message' 或者其他 JavaScript 例外的資訊) +}</pre> + +<h2 id="Promises_容器">Promises 容器</h2> + +<p>從 ECMAScript2015 起,JavaScript 支援 {{jsxref("Promise")}} 物件,允許您控制延遲和異步操作的流程。</p> + +<p><code>Promise</code> 有以下幾種狀態:</p> + +<ul> + <li><em>pending</em>:等待中,為初始之狀態,即不是 fulfilled 也不是 rejected。</li> + <li><em>fulfilled</em>:已實現,表示操作成功完成。</li> + <li><em>rejected</em>:已拒絕,表示操作失敗。</li> + <li><em>settled</em>:已完成,表示 Promise 狀態為已實現或已拒絕,但不是等待中。</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8633/promises.png" style="height: 297px; width: 801px;"></p> + +<h3 id="使用_XHR_載入圖檔">使用 XHR 載入圖檔</h3> + +<p>這裏有個簡單的範例,使用了 <code>Promise</code> 物件與及 <code><a href="/zh-TW/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> 來載入 MDN GitHub<a href="https://github.com/mdn/promises-test/blob/gh-pages/index.html"> promise-test</a> repository 中的一張圖檔。你也可以<a href="http://mdn.github.io/promises-test/">觀看結果</a>。 每一步都有註解來讓您慢慢理解 Promise 物件與及 XHR 架構。 下面的版本沒有註解,但藉由觀察 <code>Promise</code> 物件的變動您或許可以對 promise 物件有所了解:</p> + +<pre class="brush: js">function imgLoad(url) { + return new Promise(function(resolve, reject) { + var request = new XMLHttpRequest(); + request.open('GET', url); + request.responseType = 'blob'; + request.onload = function() { + if (request.status === 200) { + resolve(request.response); + } else { + reject(Error('Image didn\'t load successfully; error code:' + + request.statusText)); + } + }; + request.onerror = function() { + reject(Error('There was a network error.')); + }; + request.send(); + }); +}</pre> + +<p>以獲得更多資訊,查看 {{jsxref("Promise")}} 參照頁面,以及<a href="/zh-TW/docs/Web/JavaScript/Guide/Using_promises">使用 Promises</a> 教學。</p> + +<div>{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> diff --git a/files/zh-tw/web/javascript/guide/details_of_the_object_model/index.html b/files/zh-tw/web/javascript/guide/details_of_the_object_model/index.html new file mode 100644 index 0000000000..5b7872afce --- /dev/null +++ b/files/zh-tw/web/javascript/guide/details_of_the_object_model/index.html @@ -0,0 +1,720 @@ +--- +title: 深入了解物件模型 +slug: Web/JavaScript/Guide/Details_of_the_Object_Model +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}</p> + +<p>JavaScript 是一種基於原型,而不是基於類的物件導向語言。由於這個根本的區別,使它在如何創建物件的層級結構,以及如何繼承屬性和它的值上,顯得有點模糊。本文將闡明這個問題。</p> + +<p>本文假設您已經有點 JavaScript 的基礎,並且用 JavaScript 的函數創建過簡單的物件。</p> + +<h2 id="class-based_vs_prototype-based_languages" name="class-based_vs_prototype-based_languages">基於類 (Class-Based) 與 基於原型 (Prototype-Based) 語言的比較</h2> + +<p>基於類的物件導向語言,比如 Java 和 C++,是建基於兩種概念之上:類和實例。</p> + +<ul> + <li><em>類(Class)</em>:定義了某一種物件所擁有的屬性(可以將 Java 中的方法和<span id="tran_1_15">屬性值</span>,以及 C++ 中的成員視為屬性)。類是抽象的事物,而不是其所描述的物件中的特定成員。例如 <code>Employee</code> 類可以用來代表所有僱員。</li> + <li><em>實例(Instance)</em>:是類產生的實體,或者說,是它的一個成員。例如, <code>Victoria</code> 可以是 <code>Employee</code> 類的一個實例,表示一個特定的僱員個體。實例具有其類完全一致的屬性(不多也不少)。</li> +</ul> + +<p>基於原型的語言(例如 JavaScript)並不存在這種區別:它只有物件。基於原型的語言具有所謂<em>原型物件(Prototypical Object)</em>的概念。新物件在初始化時以原型物件為範本獲得屬性。任何物件都可以指定其自身的屬性,在創建時或運行時都可以。而且,任何物件都可以關聯為另一個物件的<em>原型(Prototype)</em>,從而允許後者共用前者的屬性。</p> + +<h3 id="定義類">定義類</h3> + +<p>在基於類的語言中,類被定義在分開的<em>類定義(Class Definition)</em>。在類定義中,允許定義特殊的方法,稱為<em>建構函數(Constructor)</em>,用以創建該類的實例。建構函數可以指定實例屬性的初始值,以及它的初始化處理。使用 <code>new</code> 操作符和建構函數來創建類的實例。</p> + +<p>JavaScript 也遵循類似的模型,但卻沒有類定義。JavaScript 使用建構函數來定義物件的屬性及初始值,所有的 JavaScript 函數都可以作為建構函數。使用 <code>new</code> 操作符來建立實例。</p> + +<h3 id="子類_(Subclass)_和繼承_(Inheritance)">子類 (Subclass) 和繼承 (Inheritance)</h3> + +<p>基於類的語言是通過類定義來構建類的層級結構。在類定義中,可以指定新的類為一個現存的類的<em>子類</em>。子類將繼承超類的全部屬性,並可以添加新的屬性或者修改繼承的屬性。例如,假設 <code>Employee</code> 類只有 <code>name</code> 和 <code>dept</code> 屬性,而 <code>Manager</code> 是 <code>Employee</code> 的子類並添加了 <code>reports</code> 屬性。這時,<code>Manager</code> 類的實例將具有三個屬性:<code>name,</code><code>dept 和</code> <code>reports</code>。</p> + +<p>JavaScript 的繼承通過關聯另一個有構建函數的原型物件來實現,這樣,您可以創建完全一樣的 <code>Employee</code> — <code>Manager</code> 範例,不過使用的方法略有不同。首先,定義 <code>Employee</code> 構建函數,指定 <code>name</code> 和 <code>dept</code> 屬性。然後,定義 <code>Manager</code> 構建函數,指定 <code>reports</code> 屬性。最後,將一個新的 <code>Employee</code> 物件賦值給 <code>Manager</code> 構建函數的 <code>prototype</code> 屬性。這樣,當創建一個新的 <code>Manager</code> 物件時,它將從 <code>Employee</code> 物件中繼承 <code>name</code> 及 <code>dept</code> 屬性。</p> + +<h3 id="添加和移除屬性">添加和移除屬性</h3> + +<p>在基於類的語言中,通常要在編譯時建立類,然後在編譯時或者運行時產生實例。一旦定義了類,便無法改變類的屬性數目或者類型。但在 JavaScript 中,允許運行時增加或者移除任何物件的屬性。如果在物件的原型物件中增加屬性,則以該物件作為原型的所有物件也將獲得該屬性。</p> + +<h3 id="區別摘要">區別摘要</h3> + +<p>下面的表格列出了上述區別。本節的後續部分將描述有關使用 JavaScript 構建函數和原型創建物件層級結構的詳細資訊,並與在 Java 中的做法做對比。</p> + +<table class="fullwidth-table"> + <caption>表 8.1 基於類(Java)和基於原型(JavaScript)的物件系統的比較</caption> + <thead> + <tr> + <th scope="col">基於類的(Java)</th> + <th scope="col">基於原型的(JavaScript)</th> + </tr> + </thead> + <tbody> + <tr> + <td>類和實例是不同的事物。</td> + <td>所有物件均為實例。</td> + </tr> + <tr> + <td>通過類定義來定義類;通過建構函數來產生實體。</td> + <td>通過建構函數來定義和創建一組物件。</td> + </tr> + <tr> + <td>通過 <code>new</code> 操作符來創建物件。</td> + <td>相同。</td> + </tr> + <tr> + <td>通過類定義來定義現存類的子類,從而建構物件的層級結構。</td> + <td>通過將一個物件作為原型指定關聯於建構函數來建構物件的層級結構。</td> + </tr> + <tr> + <td>遵循類鏈繼承屬性。</td> + <td>遵循原型鏈繼承屬性。</td> + </tr> + <tr> + <td>類定義指定類的所有實例的<em>所有</em>屬性。無法在運行時添加屬性。</td> + <td>建構函數或原型指定初始的屬性集。允許動態地向單個的物件或者整個物件集中添加屬性,或者從中移除屬性。</td> + </tr> + </tbody> +</table> + +<h2 id="僱員示例">僱員示例</h2> + +<p>本節的餘下部分將使用如下圖所示的僱員層級結構。</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4452/=figure8.1.png" style="height: 194px; width: 281px;"></p> + +<p><small><strong>圖例 8.1:一個簡單的物件層級</strong></small></p> + +<p>該示例中使用以下物件:</p> + +<ul> + <li><code>Employee</code> 具有 <code>name</code> 屬性(其值預設為空的字串)和 <code>dept</code> 屬性(其值預設為 "general")。</li> + <li><code>Manager</code> 基於 <code>Employee。它添加了</code> <code>reports</code> 屬性(其值預設為空的陣列,意在以 <code>Employee</code> 物件的陣列作為它的值)。</li> + <li><code>WorkerBee</code> 同樣基於 <code>Employee</code>。它添加了 <code>projects</code> 屬性(其值預設為空的陣列,意在以字串陣列作為它的值)。</li> + <li><code>SalesPerson</code> 基於 <code>WorkerBee</code>。它添加了 <code>quota</code> 屬性(其值預設為 100)。它還重載了 <code>dept</code> 屬性值為 "sales",表明所有的銷售人員都屬於同一部門。</li> + <li><code>Engineer</code> 基於 <code>WorkerBee</code>。它添加了 <code>machine</code> 屬性(其值預設為空的字串)同時重載了 <code>dept</code> 屬性值為 "engineering"。</li> +</ul> + +<h2 id="創建層級結構">創建層級結構</h2> + +<p>有幾種不同的方式,可以用於定義適當的建構函數,藉以實現僱員的層級結構。如何選擇很大程度上取決於您希望在您的應用程式中能做到什麼。</p> + +<p>本節展現了如何使用非常簡單的(同時也是相當不靈活的)定義,使得繼承得以實現。在這些定義中,無法在創建物件時指定屬性的值。新創建的物件僅僅獲得了預設值,當然允許隨後加以修改。圖例 8.2 展現了這些簡單的定義形成的層級結構。</p> + +<p>在 真實的應用程式中,您很可能想定義允許在創建物件時給出屬性值的建構函數。(參見 <a href="#更靈活的建構函數">更靈活的建構函數</a> 獲得進一步的資訊)。對於現在而言,這些簡單的定義示範了繼承是如何發生的。</p> + +<p><img alt="figure8.2.png" class="default internal" src="/@api/deki/files/4390/=figure8.2.png"><br> + <small><strong>圖例 8.2:Employee 物件定義</strong></small></p> + +<p>以下 <code>Employee</code> 的 Java 和 JavaScript 的定義相類似。唯一的不同是在 Java 中需要指定每個屬性的類型,而在 JavaScript 中則不必指定,同時 Java 的類必須創建一個顯式的建構函數方法。</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js"> +function Employee () { + this.name = ""; + this.dept = "general"; +} +</pre> + </td> + <td> + <pre class="brush: java"> +public class Employee { + public String name; + public String dept; + public Employee () { + this.name = ""; + this.dept = "general"; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p><code>Manager</code> 和 <code>WorkerBee</code> 的定義顯示了在如何指定繼承鏈中上一層物件方面的不同點。在 JavaScript 中,需要為建構函數的 <code>prototype</code> 屬性添加一個原型實例作為它的屬性值。您可以在定義了建構函數之後的任何時間添加這一屬性。而在 Java 中,則需要在類定義中指定超類,且不能在類定義之外改變超類。</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js"> +function Manager () { + this.reports = []; +} +Manager.prototype = new Employee; + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; +</pre> + </td> + <td> + <pre class="brush: java"> +public class Manager extends Employee { + public Employee[] reports; + public Manager () { + this.reports = new Employee[0]; + } +} + +public class WorkerBee extends Employee { + public String[] projects; + public WorkerBee () { + this.projects = new String[0]; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p><code>Engineer</code> 和 <code>SalesPerson</code> 的定義創建了派生自 <code>WorkerBee</code> 進而派生自 <code>Employee</code> 的物件。這些類型的物件將具有在這個鏈之上的所有物件的屬性。同時,這些定義重載了繼承的 <code>dept</code> 屬性值,賦予這些屬性特定於這些物件的新的屬性值。</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js"> +function SalesPerson () { + this.dept = "sales"; + this.quota = 100; +} +SalesPerson.prototype = new WorkerBee; + +function Engineer () { + this.dept = "engineering"; + this.machine = ""; +} +Engineer.prototype = new WorkerBee; +</pre> + </td> + <td> + <pre class="brush: java"> +public class SalesPerson extends WorkerBee { + public double quota; + public SalesPerson () { + this.dept = "sales"; + this.quota = 100.0; + } +} + +public class Engineer extends WorkerBee { + public String machine; + public Engineer () { + this.dept = "engineering"; + this.machine = ""; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>使用這些定義,可以創建這些物件的實例。這些實例將獲得其屬性的預設值。圖例 8.3 展現了使用這些 JavaScript 定義創建新定義,並顯示了新物件中的屬性值。</p> + +<p>{{ note('術語 <em><em>實例(instance)</em></em>在 基於類的語言中具有特定的技術含義。在這些語言中,實例是指類的個體成員,與類有著根本性的不同。在 JavaScript 中,“實例”並不具有這種技術含義,因為 JavaScript 中不存在類和實例之間的這種差異。然而,在談論 JavaScript 時,“實例”可以非正式地用於表示用特定的建構函數創建的物件。所以,在這個例子中,你可以非正式地 <code>jane</code> 是 <code>Engineer</code> 的一個實例。與之類似,儘管術語<em>父(parent)</em>,<em>子(child)</em>,<em>祖先(ancestor)</em>,和<em>後代(descendant)</em>在 JavaScript 中並沒有正式的含義,您可以非正式地使用這些術語用於指代原型鏈中處於更高層次或者更低層次的物件。') }}</p> + +<p><img alt="figure8.3.png" class="default internal" id="figure8.3" src="/@api/deki/files/4403/=figure8.3.png"><br> + <a id="8.3" name="8.3"><small><strong>圖例 8.3:通過簡單的定義創建物件</strong></small></a></p> + +<h2 id="物件的屬性">物件的屬性</h2> + +<p>本節將討論物件如何從原型鏈中的其它物件中繼承屬性,以及在運行時添加屬性的相關細節。</p> + +<h3 id="繼承屬性">繼承屬性</h3> + +<p>假設通過如下語句創建一個 <code>mark</code> 物件作為 <code>WorkerBee</code>(如 <a href="#8.3">圖例 8.3</a> 所示):</p> + +<pre class="brush: js">var mark = new WorkerBee; +</pre> + +<p>當 JavaScript 發現 <code>new</code> 操作符,它將創建一個普通的物件,並將其作為關鍵字 <code>this</code> 的值傳遞給 <code>WorkerBee</code> 的建構函數。該建構函數顯式地設置 <code>projects</code> 屬性的值,然後隱式地將其內部的 <code>__proto__</code> 屬性設置為 <code>WorkerBee.prototype</code> 的值(屬性的名稱前後均有兩個底線)。<code>__proto__</code> 屬性決定了用於返回屬性值的原型鏈。一旦這些屬性得以設置,JavaScript 返回新創建的物件,然會設定陳述式設置變數 <code>mark</code> 的值為該物件。</p> + +<p>這個過程不會顯式地為 <code>mark</code> 物件從原型鏈中所繼承的屬性設置值(本地值)。當請求屬性的值時,JavaScript 將首先檢查物件自身中是否設置了該屬性的值,如果有,則返回該值。如果本地值不存在,則 JavaScript 將檢查原型鏈(通過 <code>__proto__</code> 屬性)。如果原型鏈中的某個物件具有該屬性的值,則返回這個值。如果沒有找到該屬性,JavaScript 則認為物件中不存在該屬性。這樣,<code>mark</code> 物件中將具有如下的屬性和對應的值:</p> + +<pre class="brush: js">mark.name = ""; +mark.dept = "general"; +mark.projects = []; +</pre> + +<p><code>mark</code> 對象從 <code>mark.__proto__</code> 中保存的原型物件中繼承了 <code>name</code> 和 <code>dept</code> 屬性的值。並由 <code>WorkerBee</code> 建構函數為 <code>projects</code> 屬性設置了本地值。 這就是 JavaScript 中的屬性和屬性值的繼承。這個過程的一些微妙之處將在 <a href="#再談屬性繼承">再談屬性繼承</a> 中進一步討論。</p> + +<p>由於這些建構函數不支援設置實例特定的值,所以,這些屬性值僅僅是泛泛地由創建自 <code>WorkerBee</code> 的所有物件所共用的預設值。當然,允許修改這些屬性的值。所以,您也可以為這些屬性指定特定的值,如下所示:</p> + +<pre class="brush: js">mark.name = "Doe, Mark"; +mark.dept = "admin"; +mark.projects = ["navigator"];</pre> + +<h3 id="添加屬性">添加屬性</h3> + +<p>在 JavaScript 中,可以在運行時為任何物件添加屬性,而不必受限於建構函數提供的屬性。添加特定於某個物件的屬性,只需要為該物件指定一個屬性值,如下所示:</p> + +<pre class="brush: js">mark.bonus = 3000; +</pre> + +<p>這樣 <code>mark</code> 物件就有了 <code>bonus</code> 屬性,而其它 <code>WorkerBee</code> 則沒有該屬性。</p> + +<p>如果向某個建構函數的原型物件中添加新的屬性,則該屬性將添加到從這個原型中繼承屬性的所有物件的中。例如,可以通過如下的語句向所有僱員中添加 <code>specialty</code> 屬性:</p> + +<pre class="brush: js">Employee.prototype.specialty = "none"; +</pre> + +<p>一旦 JavaScript 執行該語句,則 <code>mark</code> 物件也將具有 <code>specialty</code> 屬性,其值為 <code>"none"</code>。下圖展現了在 <code>Employee</code> 原型中添加該屬性,然後在 <code>Engineer</code> 的原型中重載該屬性的效果。</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4422/=figure8.4.png" style="height: 519px; width: 833px;"><br> + <small><strong>Figure 8.4: Adding properties</strong></small></p> + +<h2 id="more_flexible_constructors" name="more_flexible_constructors"><a name="更靈活的建構函數">更靈活的建構函數</a></h2> + +<p>到目前為止所展現的建構函數不允許在創建新的實例時指定屬性值。正如 Java 一樣,可以為建構函數提供參數以便初始化實例的屬性值。下圖展現其中一種做法。</p> + +<p><img alt="" class="internal" id="figure8.5" src="/@api/deki/files/4423/=figure8.5.png" style="height: 481px; width: 1012px;"><br> + <a id="8.5" name="8.5"><small><strong>Figure 8.5: Specifying properties in a constructor, take 1</strong></small></a></p> + +<p>下面的表格中羅列了這些物件在 Java 和 JavaScript 中的定義。</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <pre class="brush: js"> +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; +} +</pre> + </td> + <td> + <pre class="brush: java"> +public class Employee { + public String name; + public String dept; + public Employee () { + this("", "general"); + } + public Employee (String name) { + this(name, "general"); + } + public Employee (String name, String dept) { + this.name = name; + this.dept = dept; + } +} +</pre> + </td> + </tr> + <tr> + <td> + <pre class="brush: js"> +function WorkerBee (projs) { + this.projects = projs || []; +} +WorkerBee.prototype = new Employee; +</pre> + </td> + <td> + <pre class="brush: java"> +public class WorkerBee extends Employee { + public String[] projects; + public WorkerBee () { + this(new String[0]); + } + public WorkerBee (String[] projs) { + projects = projs; + } +} + +</pre> + </td> + </tr> + <tr> + <td> + <pre class="brush: js"> + +function Engineer (mach) { + this.dept = "engineering"; + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; +</pre> + </td> + <td> + <pre class="brush: java"> +public class Engineer extends WorkerBee { + public String machine; + public Engineer () { + dept = "engineering"; + machine = ""; + } + public Engineer (String mach) { + dept = "engineering"; + machine = mach; + } +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>這些 JavaScript 定義使用了設置預設值的一種特殊慣用法:</p> + +<pre class="brush: js">this.name = name || ""; +</pre> + +<p>JavaScript 的邏輯 OR 操作符(<code>||)</code>將求解它的第一個參數。如果該參數的值可以轉換為真,則操作符返回該值。否則,操作符返回第二個參數的值。因此,這行代碼首先檢查 <code>name</code> 是否具有一個對 <code>name</code> 屬性有用的值。如果有,則設置其為 <code>this.name</code> 的值。否則,設置 <code>this.name</code> 的值為空的字串。為求簡潔,本章將使用這一慣用法,儘管咋一看它有些費解。</p> + +<p>{{ note('如果調用建構函數時,指定了可以轉換為 <code><code>false</code></code> 的參數(比如 <code>0</code> (零)和空字串<code><code>("")),結果可能出乎調用者意料。此時,將使用預設值(譯者注:而不是指定的參數值 0 和 "")。</code></code>') }}</p> + +<p>基於這些定義,當創建物件的實例時,可以為本地定義的屬性指定值。正如 <a href="#8.5">圖例 8.5</a> 所示一樣,您可以通過如下語句創建新的 <code>Engineer</code>:</p> + +<pre class="brush: js">var jane = new Engineer("belau"); +</pre> + +<p>此時,<code>Jane</code> 的屬性如下所示:</p> + +<pre class="brush: js">jane.name == ""; +jane.dept == "engineering"; +jane.projects == []; +jane.machine == "belau" +</pre> + +<p>基於上述定義,無法為諸如 <code>name</code> 這樣的繼承屬性指定初始值。在 JavaScript 中,如果想為繼承的屬性指定初始值,建構函數中需要更多的代碼。</p> + +<p>到目前為止,建構函數已經能夠創建一個普通物件,然後為新物件指定本地的屬性和屬性值。您還可以通過直接調用原型鏈上的更高層次物件的建構函數,讓建構函數添加更多的屬性。下面的圖例展現這種新定義。</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4430/=figure8.6.png" style="height: 534px; width: 1063px;"><br> + <small><strong>Figure 8.6 Specifying properties in a constructor, take 2</strong></small></p> + +<p>讓我們仔細看看這些定義的其中之一。以下是 <code>Engineer</code> 建構函數的定義:</p> + +<pre class="brush: js">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + +<p>假設您創建了一個新的 <code>Engineer</code> 物件,如下所示:</p> + +<pre class="brush: js">var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +</pre> + +<p>JavaScript 遵循以下步驟:</p> + +<ol> + <li><code>new</code> 操作符創建了一個新的普通物件,並將其 <code>__proto__</code> 屬性設置為 <code>Engineer.prototype</code>。</li> + <li><code>new</code> 操作符將該新對象作為 <code>this</code> 關鍵字的值傳遞給 <code>Engineer</code> 建構函數。</li> + <li>建構函數為該新物件創建了一個名為 <code>base</code> 的新屬性,並將 <code>WorkerBee</code> 的建構函數指定為 <code>base</code> 屬性的值。這使得 <code>WorkerBee</code> 建構函數成為 <code>Engineer</code> 物件的一個方法。<code>base</code> 屬性的名字沒有特殊性。可以使用任何合法的屬性名稱;<code>base</code> 僅僅是為了貼近它的用意。</li> + <li> + <p>建構函數調用 <code>base</code> 方法,將傳遞給該建構函數的參數中的兩個,作為參數傳遞給 <code>base</code> 方法,同時還傳遞一個字串參數 <code>"engineering"。顯式地在建構函數中使用</code> <code>"engineering"</code> 表明所有 <code>Engineer</code> 物件繼承的 <code>dept</code> 屬性具有相同的值,且該值重載了繼承自 <code>Employee</code> 的值。</p> + </li> + <li>因為 <code>base</code> 是 <code>Engineer</code> 的一個方法,在調用 <code>base</code> 時,JavaScript 將在步驟 1 中創建的對象綁定給 <code>this</code> 關鍵字。這樣,<code>WorkerBee</code> 函數接著將 <code>"Doe, Jane"</code> 和 <code>"engineering"</code> 參數傳遞給 <code>Employee</code> 建構函數。當從 <code>Employee</code> 建構函數返回時,<code>WorkerBee</code> 函數用剩下的參數設置 <code>projects</code> 屬性。</li> + <li>當從 <code>base</code> 方法返回時,<code>Engineer</code> 建構函數將物件的 <code>machine</code> 屬性初始化為 <code>"belau"</code>。</li> + <li>當從建構函數返回時,JavaScript 將新物件賦值給 <code>jane</code> 變數。</li> +</ol> + +<p>您可以認為,在 <code>Engineer</code> 的建構函數中調用 <code>WorkerBee</code> 的建構函數,也就為 <code>Engineer</code> 物件設置好了適當繼承。事實並非如此。調用 <code>WorkerBee</code> 建構函數確保了<code>Engineer</code> 物件以所有被調用的建構函數中所指定的屬性作為起步。但是,如果之後在 <code>Employee</code> 或者 <code>WorkerBee</code> 原型中添加了屬性,那些屬性不會被 <code>Engineer</code> 物件繼承。例如,假設如下語句:</p> + +<pre class="brush: js">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +Employee.prototype.specialty = "none"; +</pre> + +<p>物件 <code>jane</code> 不會繼承 <code>specialty</code> 屬性。必需顯式地設置原型才能確保動態的技能。假設修改為如下的語句:</p> + +<pre class="brush: js">function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; +var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); +Employee.prototype.specialty = "none"; +</pre> + +<p>現在 <code>jane</code> 物件的 <code>specialty</code> 屬性為 "none" 了。</p> + +<p>繼承的另一種途徑是使用<a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global Objects/Function/call"><code>call()</code></a> / <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global Objects/Function/apply"><code>apply()</code></a> 方法。下面的方式都是等價的:</p> + +<table> + <tbody> + <tr> + <td> + <pre class="brush: js"> +function Engineer (name, projs, mach) { + this.base = WorkerBee; + this.base(name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + </td> + <td> + <pre class="brush: js"> +function Engineer (name, projs, mach) { + WorkerBee.call(this, name, "engineering", projs); + this.machine = mach || ""; +} +</pre> + </td> + </tr> + </tbody> +</table> + +<p>使用 javascript 的 <code>call()</code> 方法相對明瞭一些,因為無需 <code>base</code> 方法了。</p> + +<h2 id="再談屬性的繼承">再談屬性的繼承</h2> + +<p>前面的小節中描述了 JavaScript 建構函數和原型如何提供層級結構和繼承的實現。本節中將討論之前未曾明確的一些細微之處。</p> + +<h3 id="本地的值和繼承的值">本地的值和繼承的值</h3> + +<p>正如本章前面所述,在訪問一個物件的屬性時,JavaScript 將按照如下的步驟處理:</p> + +<ol> + <li>檢查是否存在本地的值。如果存在,返回該值。</li> + <li>如果本地值不存在,檢查原型鏈(通過 <code>__proto__</code> 屬性)。</li> + <li>如果原型鏈中的某個物件具有指定屬性的值,則返回該值。</li> + <li>如果這樣的屬性不存在,則物件沒有該屬性。</li> +</ol> + +<p>以上步驟的結果依賴於您是如何定義的。最早的例子中具有如下定義:</p> + +<pre class="brush: js">function Employee () { + this.name = ""; + this.dept = "general"; +} + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; +</pre> + +<p>基於這些定義,假定通過如下的語句創建 <code>WorkerBee</code> 的實例 <code>amy:</code></p> + +<pre class="brush: js">var amy = new WorkerBee; +</pre> + +<p>則 <code>amy</code> 物件將具有一個本地屬性,<code>projects。</code><code>name</code> 和 <code>dept</code> 屬性則不是 <code>amy</code> 物件本地的,而是從 <code>amy</code> 物件的 <code>__proto__</code> 屬性獲得的。因此,<code>amy</code> 將具有如下的屬性值:</p> + +<pre class="brush: js">amy.name == ""; +amy.dept == "general"; +amy.projects == []; +</pre> + +<p>現在,假定修改了關聯於 <code>Employee</code> 的原型中的 <code>name</code> 屬性的值:</p> + +<pre class="brush: js">Employee.prototype.name = "Unknown" +</pre> + +<p>乍一看,您可能期望新的值會傳播給所有 <code>Employee</code> 的實例。然而,並非如此。</p> + +<p>在創建 <code>Employee</code> 對象的 <em>任何</em> 實例時,該實例的 <code>name</code> 屬性將獲得一個本地值(空的字串)。這意味著在創建一個新的 <code>Employee</code> 物件作為 <code>WorkerBee</code> 的原型時,<code>WorkerBee.prototype</code> 的 <code>name</code> 屬性將具有一個本地值。這樣,當 JavaScript 查找 <code>amy</code> 物件(<code>WorkerBee</code> 的實例)的 <code>name</code> 屬性時,JavaScript 將找到 <code>WorkerBee.prototype</code> 中的本地值。因此,也就不會繼續在原型鏈中向上找到 <code>Employee.prototype</code> 了。</p> + +<p>如果想在運行時修改物件的屬性值並且希望該值被所有該物件的後代所繼承,不能在該物件的建構函數中定義該屬性。而是應該將該屬性添加到該物件所關聯的原型中。例如,假設將前面的代碼作如下修改:</p> + +<pre class="brush: js">function Employee () { + this.dept = "general"; +} +Employee.prototype.name = ""; + +function WorkerBee () { + this.projects = []; +} +WorkerBee.prototype = new Employee; + +var amy = new WorkerBee; + +Employee.prototype.name = "Unknown"; +</pre> + +<p>這時,<code>amy</code> 的 <code>name</code> 屬性將為 "Unknown"。</p> + +<p>正如這些例子所示,如果希望物件的屬性具有預設值,且希望在運行時修改這些預設值,應該在物件的原型中設置這些屬性,而不是在建構函數中。</p> + +<h3 id="判斷實例的關係">判斷實例的關係</h3> + +<p>JavaScript 的屬性查找機制首先在物件自身的屬性中查找,如果指定的屬性名稱沒有找到,將在物件的特殊屬性 <code>__proto__</code> 中查找。這個過程是遞迴的;被稱為“在原型鏈中查找”。</p> + +<p>特殊的 <code>__proto__</code> 屬性是在構建物件時設置的;設置為建構函數的 <code>prototype</code> 屬性的值。所以運算式 <code>new Foo()</code> 將創建一個物件,其 <code>__proto__ == <code class="moz-txt-verticalline">Foo.prototype</code></code>。因而,修改 <code class="moz-txt-verticalline">Foo.prototype</code> 的屬性,將改變所有通過 <code>new Foo()</code> 創建的物件的屬性的查找。</p> + +<p>每個物件都有一個 <code>__proto__</code> 物件屬性(除了 <code>Object);每個函數都有一個</code> <code>prototype</code> 物件屬性。因此,通過“原型繼承(prototype inheritance)”,物件與其它物件之間形成關係。通過比較物件的 <code>__proto__</code> 屬性和函數的 <code>prototype</code> 屬性可以檢測物件的繼承關係。JavaScript 提供了便捷方法:<code>instanceof</code> 操作符可以用來將一個物件和一個函數做檢測,如果物件繼承自函數的原型,則該操作符返回真。例如:</p> + +<pre class="brush: js">var f = new Foo(); +var isTrue = (f instanceof Foo);</pre> + +<p>作為詳細一點的例子,假定我們使用和在 <a href="#繼承屬性">繼承屬性</a> 中相同的一組定義。創建 <code>Engineer</code> 物件如下:</p> + +<pre class="brush: js">var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji"); +</pre> + +<p>對於該物件,以下所有語句均為真:</p> + +<pre class="brush: js">chris.__proto__ == Engineer.prototype; +chris.__proto__.__proto__ == WorkerBee.prototype; +chris.__proto__.__proto__.__proto__ == Employee.prototype; +chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype; +chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null; +</pre> + +<p>基於此,可以寫出一個如下所示的 <code>instanceOf</code> 函數:</p> + +<pre class="brush: js">function instanceOf(object, constructor) { + while (object != null) { + if (object == constructor.prototype) + return true; + if (typeof object == 'xml') { + return constructor.prototype == XML.prototype; + } + object = object.__proto__; + } + return false; +} +</pre> + +<div class="note"><strong>Note:</strong> 在上面的實現中,檢查物件的類型是否為 "xml" 的目的在於解決新近版本的 JavaScript 中表達 XML 物件的特異之處。如果您想瞭解其中瑣碎細節,可以參考 {{ bug(634150) }}。</div> + +<pre class="brush: js">instanceOf (chris, Engineer) +instanceOf (chris, WorkerBee) +instanceOf (chris, Employee) +instanceOf (chris, Object) +</pre> + +<p>但如下運算式為假:</p> + +<pre class="brush: js">instanceOf (chris, SalesPerson)</pre> + +<h3 id="建構函數中的全域資訊">建構函數中的全域資訊</h3> + +<p>在創建建構函數時,在建構函數中設置全域資訊要小心。例如,假設希望為每一個僱員分配一個唯一標識。可能會為 <code>Employee</code> 使用如下定義:</p> + +<pre class="brush: js">var idCounter = 1; + +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + this.id = idCounter++; +} +</pre> + +<p>基於該定義,在創建新的 <code>Employee</code> 時,建構函數為其分配了序列中的下一個識別字。然後遞增全域的識別字計數器。因此,如果,如果隨後的語句如下,則 <code>victoria.id</code> 為 1 而 <code>harry.id</code> 為 2:</p> + +<pre class="brush: js">var victoria = new Employee("Pigbert, Victoria", "pubs") +var harry = new Employee("Tschopik, Harry", "sales") +</pre> + +<p>乍一看似乎沒問題。但是,無論什麼目的,在每一次創建 <code>Employee</code> 對象時,<code>idCounter</code> 都將被遞增一次。如果創建本章中所描述的整個 <code>Employee</code> 層級結構,每次設置原型的時候,<code>Employee</code> 建構函數都將被調用一次。假設有如下代碼:</p> + +<pre class="brush: js">var idCounter = 1; + +function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + this.id = idCounter++; +} + +function Manager (name, dept, reports) {...} +Manager.prototype = new Employee; + +function WorkerBee (name, dept, projs) {...} +WorkerBee.prototype = new Employee; + +function Engineer (name, projs, mach) {...} +Engineer.prototype = new WorkerBee; + +function SalesPerson (name, projs, quota) {...} +SalesPerson.prototype = new WorkerBee; + +var mac = new Engineer("Wood, Mac"); +</pre> + +<p>還可以進一步假設上面省略掉的定義中包含 <code>base</code> 屬性而且調用了原型鏈中高於它們的建構函數。即便在現在這個情況下,在 <code>mac</code> 物件創建時,<code>mac.id</code> 為 5。</p> + +<p>依賴于應用程式,計數器額外的遞增可能有問題,也可能沒問題。如果確實需要準確的計數器,則以下建構函數可以作為一個可行的方案:</p> + +<pre class="brush: js">function Employee (name, dept) { + this.name = name || ""; + this.dept = dept || "general"; + if (name) + this.id = idCounter++; +} +</pre> + +<p>在用作原型而創建新的 <code>Employee</code> 實例時,不會指定參數。使用這個建構函數定義,如果不指定參數,建構函數不會指定識別字,也不會遞增計數器。而如果想讓 <code>Employee</code> 分配到識別字,則必需為僱員指定姓名。在這個例子中,<code>mac.id</code> 將為 1。</p> + +<h3 id="沒有多繼承">沒有多繼承</h3> + +<p>某些物件導向語言支援多重繼承。也就是說,物件可以從無關的多個父物件中繼承屬性和屬性值。JavaScript 不支持多重繼承。</p> + +<p>JavaScript 屬性值的繼承是在運行時通過檢索物件的原型鏈來實現的。因為物件只有一個原型與之關聯,所以 JavaScript 無法動態地從多個原型鏈中繼承。</p> + +<p>在 JavaScript 中,可以在建構函數中調用多個其它的建構函數。這一點造成了多重繼承的假像。例如,考慮如下語句:</p> + +<pre class="brush: js">function Hobbyist (hobby) { + this.hobby = hobby || "scuba"; +} + +function Engineer (name, projs, mach, hobby) { + this.base1 = WorkerBee; + this.base1(name, "engineering", projs); + this.base2 = Hobbyist; + this.base2(hobby); + this.machine = mach || ""; +} +Engineer.prototype = new WorkerBee; + +var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo") +</pre> + +<p>進一步假設使用本章前面所屬的 <code>WorkerBee</code> 的定義。此時 <code>dennis</code> 物件具有如下屬性:</p> + +<pre class="brush: js">dennis.name == "Doe, Dennis" +dennis.dept == "engineering" +dennis.projects == ["collabra"] +dennis.machine == "hugo" +dennis.hobby == "scuba" +</pre> + +<p><code>dennis</code> 確實從 <code>Hobbyist</code> 建構函數中獲得了 <code>hobby</code> 屬性。但是,假設添加了一個屬性到 <code>Hobbyist</code> 建構函數的原型:</p> + +<pre class="brush: js">Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"] +</pre> + +<p><code>dennis</code> 物件不會繼承這個新屬性。</p> + +<div>{{ PreviousNext("JavaScript/Guide/Predefined_Core_Objects", "JavaScript/Guide/Inheritance_Revisited") }}</div> diff --git a/files/zh-tw/web/javascript/guide/expressions_and_operators/index.html b/files/zh-tw/web/javascript/guide/expressions_and_operators/index.html new file mode 100644 index 0000000000..2792b5682a --- /dev/null +++ b/files/zh-tw/web/javascript/guide/expressions_and_operators/index.html @@ -0,0 +1,934 @@ +--- +title: 運算式與運算子 +slug: Web/JavaScript/Guide/Expressions_and_Operators +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> + +<p class="summary">這個章節將講述 JavaScript 的運算式與運算子,包括賦值運算子,比較運算子,算術運算子,位元運算子, 邏輯運算子, 字串運算子, 條件(三元)運算子 以及更多運算子.</p> + +<p>更多關於運算子以及運算式的資料可以在 <a href="/en-US/docs/Web/JavaScript/Reference/Operators">reference</a> 中找到。</p> + +<h2 id="運算子">運算子</h2> + +<p>JavaScript 有以下幾種運算子。 此處將描述運算子以及一些運算子的優先順序。</p> + +<ul> + <li>{{ web.link("#賦值運算子", "賦值運算子") }}</li> + <li>{{ web.link("#比較運算子", "比較運算子") }}</li> + <li>{{ web.link("#算術運算子", "算術運算子") }}</li> + <li>{{ web.link("#位元運算子", "位元運算子") }}</li> + <li>{{ web.link("#邏輯運算子", "邏輯運算子") }}</li> + <li>{{ web.link("#字串運算子", "字串運算子") }}</li> + <li>{{ web.link("#條件(三元)運算子", "條件(三元)運算子")}}</li> + <li>{{ web.link("#逗點運算子", "逗點運算子")}}</li> + <li>{{ web.link("#一元運算子", "一元運算子")}}</li> + <li>{{ web.link("#關係運算子", "關係運算子")}}</li> +</ul> + +<p>JavaScript 同時具有二元運算子及一元運算子, 以及一種特殊的 三元運算子,也就是 條件運算子。 一個二元運算子需要具備兩個運算元, 一個在運算元之前,一個在運算元之後:</p> + +<pre class="syntaxbox notranslate"><em>運算元1</em> <em>運算子</em> <em>運算元2</em> +</pre> + +<p>例如, <code>3+4</code> 或 <code>x*y</code>.</p> + +<p>一個 一元運算子 需要一個運算元, 位於運算子之前或之後:</p> + +<pre class="syntaxbox notranslate"><em>運算子</em> <em>運算元</em> +</pre> + +<p>或</p> + +<pre class="syntaxbox notranslate"><em>運算元 運算子</em> +</pre> + +<p>例如, <code>x++</code> 或 <code>++x</code>.</p> + +<h3 id="賦值運算子">賦值運算子</h3> + +<p>一個 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators">賦值運算子</a> 將 基於其 右方的運算元 的值賦予其 左方的運算元。 最簡單的 賦值運算子 是 等於 (<code>=</code>), 它將賦予 左方運算元 與 右方運算元相同之值。 也就是, <code>x = y</code> 會把y的值賦予給x。</p> + +<p>也有一些復合的 賦值運算子 是為了縮短下面表中的運算:</p> + +<table class="standard-table"> + <caption>復合運算子</caption> + <thead> + <tr> + <th>名稱</th> + <th>簡化的運算子</th> + <th>意義</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x = y</code></td> + <td><code>x = y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Addition_assignment">加法</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x += y</code></td> + <td><code>x = x + y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Subtraction_assignment">減法</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x -= y</code></td> + <td><code>x = x - y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Multiplication_assignment">乘法</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x *= y</code></td> + <td><code>x = x * y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Division_assignment">除法</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x /= y</code></td> + <td><code>x = x / y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Remainder_assignment">餘數</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x %= y</code></td> + <td><code>x = x % y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Exponentiation_assignment">指數</a><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">賦值</a></td> + <td><code>x **= y</code></td> + <td><code>x = x ** y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Left_shift_assignment">左移賦值</a></td> + <td><code>x <<= y</code></td> + <td><code>x = x << y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Right_shift_assignment">右移賦值</a></td> + <td><code>x >>= y</code></td> + <td><code>x = x >> y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Unsigned_right_shift_assignment">無號右移賦值</a></td> + <td><code>x >>>= y</code></td> + <td><code>x = x >>> y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_AND_assignment">位元 AND 賦值</a></td> + <td><code>x &= y</code></td> + <td><code>x = x & y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_XOR_assignment">位元 XOR 賦值</a></td> + <td><code>x ^= y</code></td> + <td><code>x = x ^ y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_OR_assignment">位元 OR 賦值</a></td> + <td><code>x |= y</code></td> + <td><code>x = x | y</code></td> + </tr> + </tbody> +</table> + +<h4 id="解構">解構</h4> + +<p>為了進行更複雜的賦值,<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">解構賦值</a>是 JavaScript 用來從陣列或物件中提取資料的語法。</p> + +<pre class="brush: js notranslate">var foo = ['one', 'two', 'three']; + +// 不使用解構 +var one = foo[0]; +var two = foo[1]; +var three = foo[2]; + +// 使用解構 +var [one, two, three] = foo;</pre> + +<h3 id="比較運算子">比較運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">比較運算子</a> 會比較 運算元 並基於比較的結果回傳邏輯值。 運算元可以是數字,字串,邏輯,或物件的值。 字串的比較是基於字典序的, 使用 Unicode 的值。 在多數情況下,假如兩個運算元不具有相同型態, JavaScript 會嘗試將它們轉換成相同型態。這個行為通常是將運算元以數學形式對待。 在某些的轉換型態的例外中會使用到 <code>===</code> 及 <code>!==</code> 運算子, 它們會嚴格地進行相等或不相等的比較。 這些運算子不會在確認相等與否前嘗試轉換運算元的型態。 下面的表解釋了比較運算子:</p> + +<pre class="brush: js notranslate">var var1 = 3; +var var2 = 4; +</pre> + +<table class="standard-table"> + <caption>比較運算子</caption> + <thead> + <tr> + <th scope="col">運算子</th> + <th scope="col">描述</th> + <th scope="col">會回傳True的例子</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality">等於</a> (<code>==</code>)</td> + <td>假如運算元等價就回傳True。</td> + <td><code>3 == var1</code> + <p><code>"3" == var1</code></p> + <code>3 == '3'</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Inequality">不等於</a> (<code>!=</code>)</td> + <td>假如運算元等價就回傳True。</td> + <td><code>var1 != 4<br> + var2 != "3"</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">嚴格等於</a> (<code>===</code>)</td> + <td>假如運算元具有相同型態且等價則回傳True。參考 {{jsxref("Object.is")}} 及 <a href="/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness" title="/en-US/docs/Web/JavaScript/Guide/Sameness">JS中的等價性</a>。</td> + <td><code>3 === var1</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Nonidentity">嚴格不等於</a> (<code>!==</code>)</td> + <td>假如運算元具有相同型態但不等價,或是具有不同型態,回傳True。</td> + <td><code>var1 !== "3"<br> + 3 !== '3'</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator">大於</a> (<code>></code>)</td> + <td>假如左方運算元大於右方運算元,回傳True。</td> + <td><code>var2 > var1<br> + "12" > 2</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_or_equal_operator">大於或等於</a> (<code>>=</code>)</td> + <td>假如左方運算元大於或等於右方運算元,回傳True。</td> + <td><code>var2 >= var1<br> + var1 >= 3</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_operator">小於</a> (<code><</code>)</td> + <td>假如左方運算元小於右方運算元,回傳True。</td> + <td><code>var1 < var2<br> + "2" < 12</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_or_equal_operator">小於或等於</a> (<code><=</code>)</td> + <td>假如左方運算元小於或等於右方運算元,回傳True。</td> + <td><code>var1 <= var2<br> + var2 <= 5</code></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>筆記: </strong>(<strong>=>)不是運算子,是</strong> <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭頭函式。</a></p> +</div> + +<h3 id="算術運算子">算術運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators">算術運算子</a> 以 數值 (文字或變數也可以)作為其運算元,並回傳單一數值。最常見的算術運算元是 加法 (<code>+</code>),減法 (<code>-</code>), 乘法 (<code>*</code>),及除法 (<code>/</code>)。 這些運算子在大多數程式語言中功能相同 (比較特別的是,在除數為0時 {{jsxref("Infinity")}})。例如:</p> + +<pre class="brush: js notranslate">1 / 2; // 0.5 +1 / 2 == 1.0 / 2.0; // 會是 true +</pre> + +<p>除了標準的算術運算子外 (+, -, * /), JavaScript 提供以下表中的算術運算子:</p> + +<table class="fullwidth-table"> + <caption>算術運算子</caption> + <thead> + <tr> + <th scope="col">運算子</th> + <th scope="col">描述</th> + <th scope="col">範例</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder">取餘數</a> (<code>%</code>)</td> + <td>二元運算子。回傳兩個運算元相除後的餘數。</td> + <td>12 % 5 回傳 2.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Increment">增加</a> (<code>++</code>)</td> + <td>一元運算子。 將運算元增加1。假如使用在運算元之前 (<code>++x</code>),會運算元回傳增加1後的值;假如使用在運算元之後。 (<code>x++</code>)<code>,</code> 會回傳運算元加1前的值。</td> + <td>假如 <code>x是</code> 3,那 <code>++x</code> 將把 <code>x</code> 設定為 4 並回傳 4,而 <code>x++ 會回傳</code> 3 , 接著才把 <code>x 設定為</code> 4。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Decrement">減少</a> (<code>--</code>)</td> + <td>一元運算子。 將運算元減少1。回傳值的情況與 增加運算元 相同。</td> + <td>假如 <code>x是</code> 3,那 <code>--x</code> 將把 <code>x</code> 設定為 2 並回傳 2,而 <code>x-- 會回傳</code> 3 , 接著才把 <code>x 設定為</code> 2。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_negation">(一元運算子)減號</a> (<code>-</code>)</td> + <td>一元運算子。回傳運算元的負數。</td> + <td>假如x是3,-x 回傳 -3。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus">(一元運算子)加號</a> (<code>+</code>)</td> + <td>一元運算子。嘗試將運算元轉換成數字,假如它還不是數字的話。</td> + <td><code>+"3"</code> <code>回傳 3</code>。<br> + <code>+true</code> 回傳 <code>1.</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation">指數運算子</a> (<code>**</code>) {{experimental_inline}}</td> + <td>計算以 a 為底的 <code>b</code> 次方, 也就是, a<code><sup>b</sup></code></td> + <td><code>2 ** 3</code> <code>回傳 8</code>.<br> + <code>10 ** -1</code> 回傳 <code>0.1</code>.</td> + </tr> + </tbody> +</table> + +<h3 id="位元運算子">位元運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">位元運算子</a> 把運算元當作 32 位元的集合來看待 (0和1), 而不是十進位,十六進位,或八進位。例如,十進位數字 9 以二進位表示就是 1001。 位元運算子將運算元以上述二進位的形式處理,但是回傳 Javascript 中的數字類型值。</p> + +<p>下列表總結了 JavaScript' 中的位元運算子。</p> + +<table class="standard-table"> + <caption>位元運算子</caption> + <thead> + <tr> + <th scope="col">運算子</th> + <th scope="col">用法</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_AND">位元 AND</a></td> + <td><code>a & b</code></td> + <td>回傳兩個運算元對於每個bit做AND的結果。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR">位元 OR</a></td> + <td><code>a | b</code></td> + <td>回傳兩個運算元對於每個bit做OR的結果。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_XOR">位元 XOR</a></td> + <td><code>a ^ b</code></td> + <td>回傳兩個運算元對於每個bit做XOR的結果。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT">位元 NOT</a></td> + <td><code>~ a</code></td> + <td>將運算元中的每個bit反轉(1->0,0->1)。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift">左移</a></td> + <td><code>a << b</code></td> + <td>將 <code>a</code> 的每個bit向左移動 <code>b</code> 個bits,空餘的位數以0填滿。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift">有號右移</a></td> + <td><code>a >> b</code></td> + <td>將 <code>a</code> 的每個bit向右移動 <code>b</code> 個bits,空餘位數以最高位補滿。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Unsigned_right_shift">以0填充的右移</a></td> + <td><code>a >>> b</code></td> + <td>將 <code>a</code> 的每個bit向右移動 <code>b</code> 個bits,空餘的位數以0填滿。</td> + </tr> + </tbody> +</table> + +<h4 id="Bitwise_Logical_Operators" name="Bitwise_Logical_Operators">位元邏輯運算子</h4> + +<p>概念上,位元邏輯運算子運作過程如下:</p> + +<ul> + <li>運算元被轉換為32 bits 的整數以二進位形式表示 (0 和 1)。大於 32 bits 的數字將被捨棄多出來的位元。例如, 下列整數大於32個bit但是會被轉換為32個bit的整數: + <pre class="notranslate">轉換之前: 11100110111110100000000000000110000000000001 +轉換之後: 10100000000000000110000000000001</pre> + </li> + <li>第一個運算元中的每個bit分別對應到第二個運算元的每個bit: 第一個 bit 對 第一個 bit, 第二個 bit 對 第二個 bit, 以此類推。</li> + <li>運算子會對於 bit 進行運算, 結果也是基於bit 來決定的。</li> +</ul> + +<p>例如, 9 的二元表示法是 1001, 15 的二元表示法是 1111。因此,在使用位元運算子的時候,結果如下:</p> + +<table class="standard-table"> + <caption>位元運算子範例</caption> + <thead> + <tr> + <th scope="col">運算式</th> + <th scope="col">結果</th> + <th scope="col">二元描述式</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>15 & 9</code></td> + <td><code>9</code></td> + <td><code>1111 & 1001 = 1001</code></td> + </tr> + <tr> + <td><code>15 | 9</code></td> + <td><code>15</code></td> + <td><code>1111 | 1001 = 1111</code></td> + </tr> + <tr> + <td><code>15 ^ 9</code></td> + <td><code>6</code></td> + <td><code>1111 ^ 1001 = 0110</code></td> + </tr> + <tr> + <td><code>~15</code></td> + <td><code>-16</code></td> + <td><code>~</code><code>00000000...</code><code>00001111 = </code><code>1111</code><code>1111</code><code>...</code><code>11110000</code></td> + </tr> + <tr> + <td><code>~9</code></td> + <td><code>-10</code></td> + <td><code>~</code><code>00000000</code><code>...</code><code>0000</code><code>1001 = </code><code>1111</code><code>1111</code><code>...</code><code>1111</code><code>0110</code></td> + </tr> + </tbody> +</table> + +<p>注意,在使用 位元NOT 運算子時, 所有的32個bit都被進行NOT了,包含最左邊用來描述正負數的位元(two's-complement representation)。</p> + +<h4 id="Bitwise_Shift_Operators" name="Bitwise_Shift_Operators">位元移動運算子</h4> + +<p>位元移動運算子需要兩個運算元: 第一個是運算的目標,第二個是要移動的位元數。移動的方向取決於使用的運算子。</p> + +<p>移動運算子會將運算元轉換成32 bits的整數,並且會回傳與左方運算元相同的型態。</p> + +<p>移動運算子在下表被列出.</p> + +<table class="fullwidth-table"> + <caption>位元移動運算子</caption> + <thead> + <tr> + <th scope="col">運算子</th> + <th scope="col">描述</th> + <th scope="col">範例</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#<<_(Left_shift)">左移</a><br> + (<code><<</code>)</td> + <td>這個運算子會將第 一個運算元的每個bit向左移動 第二個運算元所指定的bit數量。左邊超出的位數會被捨棄,右邊空出的位數以0補齊。</td> + <td><code>9<<2</code> 得到 36,因為1001 向左移動 2 bits 會得到 100100, 也就是二進位的 36。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#>>_(Sign-propagating_right_shift)">有號右移</a> (<code>>></code>)</td> + <td>這個運算子會將第 一個運算元的每個bit向右移動 第二個運算元所指定的bit數量。右邊超出的位數會被捨棄,左邊空出的位數以最高位補齊。</td> + <td><code>9>>2</code> 得到 2,因為 1001 向右移動 2 bits 會得到 10,也就是二進位的 2。 相同的, <code>-9>>2</code> 會得到 -3,因為最高位用來表示正負號的bit被保留了。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#>>>_(Zero-fill_right_shift)">以0填充的右移</a> (<code>>>></code>)</td> + <td>這個運算子會將第 一個運算元的每個bit向右移動 第二個運算元所指定的bit數量。右邊超出的位數會被捨棄,左邊空出的位數以0補齊。</td> + <td><code>19>>>2 得到</code> 4, 因為 10011 向右移動 2 bits 會得到 100,是二進位的 4。對於非負的數字而言, 以0填充的右移 會得到和 有號右移相同的結果。</td> + </tr> + </tbody> +</table> + +<h3 id="邏輯運算子">邏輯運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">邏輯運算子</a> 通常被用於布林(邏輯)值; 使用於 布林(邏輯)值時, 它們會回傳布林型態的值。 然而,<code>&&</code> 和 <code>||</code> 運算子實際上是回傳兩指定運算元之一,因此用於非布林型態值時,它可能會回傳一個非布林型態的值。 邏輯運算子將在下表中被詳細解釋。</p> + +<table class="fullwidth-table"> + <caption>Logical operators</caption> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Usage</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_AND">邏輯 AND</a><code> </code>(<code>&&</code>)</td> + <td><code>運算式1 && 運算式2</code></td> + <td>假如<code> 運算式1</code> 可以被轉換成 false的話,回傳 <code>運算式1</code>; 否則,回傳 <code>運算式2</code>。 因此,<code>&&</code>只有在 兩個運算元都是True 時才會回傳 True,否則回傳<code> false</code>。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR">邏輯 OR </a>(<code>||</code>)</td> + <td><code>運算式1 || 運算式2</code></td> + <td>假如<code> 運算式1</code> 可以被轉換成 true的話,回傳 <code>運算式1</code>; 否則,回傳 <code>運算式2</code>。 因此,<code>||</code>在 兩個運算元有任一個是True 時就會回傳 True,否則回傳<code> false</code>。</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT">邏輯 NOT </a>(<code>!</code>)</td> + <td><code>!運算式</code></td> + <td>假如單一個運算元能被轉換成True時,回傳<code>false</code> , 不然回傳 <code>true</code>。</td> + </tr> + </tbody> +</table> + +<p>可以被轉換為 false 的運算式是 null, 0, NaN, 空字串 (""),或 未定義。</p> + +<p>下面是 <code>&&</code> (邏輯 AND) 運算子 的範例。</p> + +<pre class="brush: js notranslate">var a1 = true && true; // t && t 回傳 true +var a2 = true && false; // t && f 回傳 false +var a3 = false && true; // f && t 回傳 false +var a4 = false && (3 == 4); // f && f 回傳 false +var a5 = "Cat" && "Dog"; // t && t 回傳 Dog +var a6 = false && "Cat"; // f && t 回傳 false +var a7 = "Cat" && false; // t && f 回傳 false +</pre> + +<p>下列是 || (邏輯 OR) 運算子的範例。</p> + +<pre class="brush: js notranslate">var o1 = true || true; // t || t 回傳 true +var o2 = false || true; // f || t 回傳 true +var o3 = true || false; // t || f 回傳 true +var o4 = false || (3 == 4); // f || f 回傳 false +var o5 = 'Cat' || 'Dog'; // t || t 回傳 Cat +var o6 = false || 'Cat'; // f || t 回傳 Cat +var o7 = 'Cat' || false; // t || f 回傳 Cat +</pre> + +<p>下列是 ! (邏輯 NOT) 運算子的範例。</p> + +<pre class="brush: js notranslate">var n1 = !true; // !t 回傳 false +var n2 = !false; // !f 回傳 true +var n3 = !'Cat'; // !t 回傳 false +</pre> + +<h4 id="Short-Circuit_Evaluation" name="Short-Circuit_Evaluation">短路解析</h4> + +<p>邏輯運算式是由左向右解析的, 他們會以下列規則嘗試進行 短路解析:</p> + +<ul> + <li><code>false</code> &&<em> 任何東西 </em> 是 false 的短路解析。</li> + <li><code>true</code> || <em>任何東西 </em> 是 true 的短路解析。</li> +</ul> + +<p>這些規則保證 解析總是正確的。 值得注意的地方是,剩餘部分的運算式並沒有被解析,所以不會占用任何效能。</p> + +<h3 id="字串運算子">字串運算子</h3> + +<p>除了作為比較運算子之外, 運算子 (+) 也能用於字串,將兩字串接在一起,並回傳接在一起後的結果。</p> + +<p>例如,</p> + +<pre class="brush: js notranslate">console.log('我的 ' + '字串'); // 會印出 字串 "我的字串"。</pre> + +<p>簡化的設定運算子 += 也能用於串接字串。</p> + +<p>例如,</p> + +<pre class="brush: js notranslate">var mystring = '字'; +mystring += '母'; // 得到 "字母" 並賦與給變數 mystring.</pre> + +<h3 id="條件(三元)運算子">條件(三元)運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">條件運算子</a> 是 JavaScript 中唯一需要三個運算元的運算子。 這個運算子接受兩個運算元作為值且一個運算元作為條件。 語法是:</p> + +<pre class="syntaxbox notranslate"><em>條件</em> ? <em>值1</em> : <em>值2</em> +</pre> + +<p>如果 <em>條件</em> 為 true,運算子回傳 <em>值1,</em> 否則回傳 <em>值2。</em> 你可以在任何使用標準運算子的地方改用 條件運算子。</p> + +<p>例如,</p> + +<pre class="brush: js notranslate">var status = (age >= 18) ? '成人' : '小孩'; +</pre> + +<p>這個陳述句會將 "成人" 賦與給變數 <code>status</code> 假如 <code>age</code> 大於等於18。 否則,會將 "小孩" 賦與給變數 <code>status</code>。</p> + +<h3 id="Comma_operator" name="Comma_operator">逗號運算子</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator">逗點運算子</a> (<code>,</code>) 作用是解析兩個運算元並回傳後面那個運算元的值。 這個運算子通常用於for迴圈內部,讓多個變數能在每次迴圈中被更新。</p> + +<p>例如,假如 <code>a</code> 是一個有十個物件在裡面的二維陣列, 下面的程式中就使用了逗點運算子來同時更新兩個變數。 這段程式碼會印出陣列中所有對角線上的物件:</p> + +<pre class="brush: js notranslate">for (var i = 0, j = 9; i <= j; i++, j--) + console.log('a[' + i + '][' + j + ']= ' + a[i][j]); +</pre> + +<h3 id="一元運算子">一元運算子</h3> + +<p>一元運算 是只需要一個運算元的運算。</p> + +<h4 id="delete" name="delete"><code>delete</code></h4> + +<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code> 運算子會刪除物件,物件的性質,或是陣列中指定 index 的物件。 語法是:</p> + +<pre class="brush: js notranslate">delete 物件名稱; +delete 物件名稱.性質; +delete 物件名稱[索引]; +delete 性質; // 只有在 with 陳述句中可以使用 +</pre> + +<p><code>物件名稱</code> 是物件的名稱, 性質 是物件中的一個特性, 索引 是用來表示物件在陣列中位置的一個整數。</p> + +<p>第四種形式只有在 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/with">with</a></code> 陳述句中可用, 用來刪除物件中的一個特性。</p> + +<p>你可以用 <code>delete</code> 運算子來刪除隱式宣告的變數, 但不適用於使用 var 宣告的變數。</p> + +<p>假如 <code>delete</code> 運算子使用成功, 它會將物件 或是 物件的特性設定為 <code>未定義。</code> <code>delete</code> 運算子會在運算成功時回傳 true ,失敗時回傳 <code>false</code> 。</p> + +<pre class="brush: js notranslate">x = 42; +var y = 43; +myobj = new Number(); +myobj.h = 4; // 建立特性 h +delete x; // 回傳 true (只有在隱式宣告時能被刪除) +delete y; // 回傳 false (在使用 var 宣告時無法刪除) +delete Math.PI; // 回傳 false (不能刪除內建定義的特性) +delete myobj.h; // 回傳 true (可以刪除使用者自定義的特性) +delete myobj; // 回傳 true (在隱式宣告時可被刪除) +</pre> + +<h5 id="刪除陣列元素">刪除陣列元素</h5> + +<p>在你刪除了陣列中的一個元素後, 陣列的長度並不會改變。 例如, 假如你<code>刪除 a[3]</code>, <code>a[4]</code> 依然是 <code>a[4]</code> 而 <code>a[3]</code> 為 未定義。</p> + +<p>當使用 <code>delete</code> 運算子刪除陣列中的一個元素後, 那個元素便不再存在於陣列中了。 在下面的程式中, <code>trees[3]</code> 被用 delete 移除了。然而, <code>trees[3]</code> 的記憶體位址仍可用並且會回傳 未定義。</p> + +<pre class="brush: js notranslate">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +delete trees[3]; +if (3 in trees) { + // 不會執行到這裡 +} +</pre> + +<p>假如你希望給予陣列元素 未定義 的值, 你可以直接使用 <code>undefined</code> 關鍵字而不是使用 delete 運算子。 下列範例中, <code>trees[3]</code> 被指定了 <code>undefined</code>, 然而陣列元素依然存在:</p> + +<pre class="brush: js notranslate">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +trees[3] = undefined; +if (3 in trees) { + // 會執行這裡 +} +</pre> + +<h4 id="typeof" name="typeof"><code>typeof</code></h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/typeof"><code>typeof</code> 運算子</a> 能以下列任一方式使用:</p> + +<pre class="syntaxbox notranslate">typeof 運算元 +typeof (運算元) +</pre> + +<p><code>typeof</code> 運算子會回傳代表運算元類型的 字串。 <code>運算元能是字串,變數,關鍵字,或是會回傳型態的物件。</code> 括號是可有可無的。</p> + +<p>假設你定義了以下這些變數:</p> + +<pre class="brush: js notranslate">var myFun = new Function('5 + 2'); +var shape = 'round'; +var size = 1; +var today = new Date(); +</pre> + +<p><code>typeof</code> 運算子會回傳下列結果:</p> + +<pre class="brush: js notranslate">typeof myFun; // 回傳 "function" +typeof shape; // 回傳 "string" +typeof size; // 回傳 "number" +typeof today; // 回傳 "object" +typeof doesntExist; // 回傳 "undefined" +</pre> + +<p>對於 <code>true</code> 和 <code>null關鍵字,</code> <code>typeof</code> 運算子會回傳下列結果:</p> + +<pre class="brush: js notranslate">typeof true; // 回傳 "boolean" +typeof null; // 回傳 "object" +</pre> + +<p>對於字串或數字, <code>typeof</code> 運算子會回傳下列結果:</p> + +<pre class="brush: js notranslate">typeof 62; // 回傳 "number" +typeof 'Hello world'; // 回傳 "string" +</pre> + +<p>對於特性,<code>typeof</code> 運算子會回傳 特性的值的類型:</p> + +<pre class="brush: js notranslate">typeof document.lastModified; // 回傳 "string" +typeof window.length; // 回傳 "number" +typeof Math.LN2; // 回傳 "number" +</pre> + +<p>對於 方法 及 函式, <code>typeof</code> 運算子會回傳下列結果:</p> + +<pre class="brush: js notranslate">typeof blur; // 回傳 "function" +typeof eval; // 回傳 "function" +typeof parseInt; // 回傳 "function" +typeof shape.split; // 回傳 "function" +</pre> + +<p>對於內建定義的物件, <code>typeof</code> 運算子會回傳下列結果:</p> + +<pre class="brush: js notranslate">typeof Date; // 回傳 "function" +typeof Function; // 回傳 "function" +typeof Math; // 回傳 "object" +typeof Option; // 回傳 "function" +typeof String; // 回傳 "function" +</pre> + +<h4 id="void" name="void"><code>void</code></h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/void"><code>void</code> 運算子 </a>能以下列任一方式使用:</p> + +<pre class="syntaxbox notranslate">void (運算式) +void 運算式 +</pre> + +<p><code>void</code> 運算子會解析運算式而不回傳任何值。 <code>運算式</code> 是 JavaScript 中要解析的對象。 括號是可有可無的,但是建議使用。</p> + +<p>你可以使用 <code>void</code> 運算子來解析超連結中的運算式。 運算式會被解析而不會在當前頁面被印出。</p> + +<p>下列範例是一個在點擊時甚麼都不做的超連結。 當使用者點擊連結時, <code>void(0)</code> 被解析為 未定義, 而甚麼都不會發生。</p> + +<pre class="brush: html notranslate"><a href="javascript:void(0)">點擊這裡,甚麼都不會發生</a> +</pre> + +<p>下列範例是一個在使用者點擊時傳送表單的超連結。</p> + +<pre class="brush: html notranslate"><a href="javascript:void(document.form.submit())"> +點擊以送出</a></pre> + +<h3 id="關係運算子">關係運算子</h3> + +<p>關係運算子比較兩運算元並基於比較結果回傳布林值。</p> + +<h4 id="in"><code>in</code></h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/in"><code>in </code>運算子</a> 在指定性質存在於物件中時回傳 true 。 語法是:</p> + +<pre class="brush: js notranslate">性質名稱 in 物件名稱 +</pre> + +<p>性質名稱 可以是 字串或數字,或是陣列的索引, 且<code> </code>物件名稱 是物件的名稱。</p> + +<p>下列範例示範了 <code>in</code> 運算子的一些用法。</p> + +<pre class="brush: js notranslate">// 陣列 +var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +0 in trees; // 回傳 true +3 in trees; // 回傳 true +6 in trees; // 回傳 false +'bay' in trees; // 回傳 false (你必須指定 索引, + // 而不是 索引所對應的元素) +'length' in trees; // 回傳 true (length 是陣列的性質之一) + +// 內建物件 +'PI' in Math; // 回傳 true +var myString = new String("coral"); +'length' in myString; // 回傳 true + +// 自訂義物件 +var mycar = { make: 'Honda', model: 'Accord', year: 1998 }; +'make' in mycar; // 回傳 true +'model' in mycar; // 回傳 true +</pre> + +<h4 id="instanceof" name="instanceof"><code>instanceof</code></h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/instanceof"><code>instanceof</code> 運算子</a> 在 指定物件 具有 指定的物件型態 時回傳 true。 語法是:</p> + +<pre class="syntaxbox notranslate">物件名稱 instanceof 物件類型 +</pre> + +<p><code>物件名稱</code> 是用來與 物件類型 比較的物件的名字, 物件類型 是物件的類型, 例如 {{jsxref("Date")}} 或 {{jsxref("Array")}}。</p> + +<p>當你需要在程式執行中確認物件的形態時,你可以使用 ins<code>tanceof</code> 運算子。 例如,當捕捉到例外時, 你可以依照例外的類型來決定用來處理意外的程式碼。</p> + +<p>例如,下列程式碼使用 <code>instanceof</code> 來判斷變數 <code>theDay</code> 是不是 <code>Date</code> 類型的物件。 因為 <code>theDay</code> 是 <code>Date</code> 類型的物件, 所以if 陳述中的陳述句會被執行。</p> + +<pre class="brush: js notranslate">var theDay = new Date(1995, 12, 17); +if (theDay instanceof Date) { + // 會被執行的陳述 +} +</pre> + +<h3 id="運算子優先級">運算子優先級</h3> + +<p>運算子優先級決定運算子被使用於運算元的先後順序。 你也可以使用括號來強制指定優先級。</p> + +<p>下列表格列出了運算子的優先級, 從高到低。</p> + +<table class="standard-table"> + <caption>運算子優先級</caption> + <thead> + <tr> + <th scope="col">運算子類型</th> + <th scope="col">屬於該類別的運算子</th> + </tr> + </thead> + <tbody> + <tr> + <td>成員</td> + <td><code>. []</code></td> + </tr> + <tr> + <td>呼叫/建立 實例</td> + <td><code>() new</code></td> + </tr> + <tr> + <td>反向/增加</td> + <td><code>! ~ - + ++ -- typeof void delete</code></td> + </tr> + <tr> + <td>乘法/除法</td> + <td><code>* / %</code></td> + </tr> + <tr> + <td>加法/減法</td> + <td><code>+ -</code></td> + </tr> + <tr> + <td>位元移動</td> + <td><code><< >> >>></code></td> + </tr> + <tr> + <td>關係運算子</td> + <td><code>< <= > >= in instanceof</code></td> + </tr> + <tr> + <td>相等性</td> + <td><code>== != === !==</code></td> + </tr> + <tr> + <td>位元 and</td> + <td><code>&</code></td> + </tr> + <tr> + <td>位元 xor</td> + <td><code>^</code></td> + </tr> + <tr> + <td>位元 or</td> + <td><code>|</code></td> + </tr> + <tr> + <td>邏輯 and</td> + <td><code>&&</code></td> + </tr> + <tr> + <td>邏輯 or</td> + <td><code>||</code></td> + </tr> + <tr> + <td>條件運算子</td> + <td><code>?:</code></td> + </tr> + <tr> + <td>指定運算子</td> + <td><code>= += -= *= /= %= <<= >>= >>>= &= ^= |=</code></td> + </tr> + <tr> + <td>逗點運算子</td> + <td><code>,</code></td> + </tr> + </tbody> +</table> + +<p>這個表格更詳細的版本,解釋了運算子的更多細節和關聯性, 可以在 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table">JavaScript 參考</a> 中被找到。</p> + +<h2 id="運算式">運算式</h2> + +<p>運算式是任何一段可以取得一個值的程式碼。</p> + +<p>任何合乎語法的運算式都能取得一個值,概念上, 有兩種不同型態的運算式: 有副作用的 (例如: 將一個值指定給一個變數) 以及只為了取得值而解析的運算式。</p> + +<p>運算式 <code>x = 7</code> 是上述的第一種類型。 這個使用 =<em> </em>運算子的運算式會將數值 7 賦與給 x。 運算式本身也會被解析為 7。</p> + +<p>運算式 <code>3 + 4</code> 是上述的第二種類型。 這個運算式使用 + 運算子把 3 和 4 加起來,而不指定給任何變數。<br> + <br> + JavaScript 運算式有下列幾種種類:</p> + +<ul> + <li>算術: 解析出數字, 例如 3.14159. (通常使用 {{ web.link("#Arithmetic_operators", "算術運算子") }}.)</li> + <li>字串: 解析出字串, 例如 "Fred" or "234"。 (通常使用 {{ web.link("#String_operators", "字串運算子") }}.)</li> + <li>邏輯: 解析出 True 或 False (通常與 {{ web.link("#Logical_operators", "邏輯運算子") }} 相關。)</li> + <li>主流運算式: JavaScript 基本的關鍵字及運算式。</li> + <li>左側運算式: 左側是指定值的對象。</li> +</ul> + +<h3 id="主流運算式">主流運算式</h3> + +<p>JavaScript 基本的關鍵字及運算式。</p> + +<h4 id="this" name="this"><code>this</code></h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/this"><code>this</code> 關鍵字</a> 能取得當前所在物件。 一般而言, <code>this</code> 能取得呼叫處所在的物件。 你可以使用 點 或是 中括號 來取用該物件中的特性:</p> + +<pre class="syntaxbox notranslate">this['特性名稱'] +this.特性名稱 +</pre> + +<p>以下定義一個叫做 <code>validate</code> 的函式,比較物件中特性 <code>value 與傳入的兩變數</code>:</p> + +<pre class="brush: js notranslate">function validate(obj, lowval, hival){ + if ((obj.value < lowval) || (obj.value > hival)) + console.log('不可用的值!'); +} +</pre> + +<p>你可以在表單的 <code>onChange</code> event handler 中呼叫 <code>validate</code> 函式, 並以 <code>this</code> 來傳入表單的元素, 範例如下:</p> + +<pre class="brush: html notranslate"><p>請輸入一介於18 與 99 的數字:</p> +<input type="text" name="age" size=3 onChange="validate(this, 18, 99);"> +</pre> + +<h4 id="分組運算子">分組運算子</h4> + +<p>分組運算子 <code>( )</code> 控制了運算子的優先順序。 例如,你可以覆寫先乘除,後加減的優先順序,使其變成先加減,後乘除。</p> + +<pre class="brush:js notranslate">var a = 1; +var b = 2; +var c = 3; + +// 預設運算級 +a + b * c // 7 +// 預設的結果 +a + (b * c) // 7 + +// 現在複寫運算級 +// 變成先進行加法,後乘法了 +(a + b) * c // 9 + +// 結果 +a * c + b * c // 9 +</pre> + +<h4 id="解析">解析</h4> + +<p>解析是 JavaScript 中的一個實驗性功能, 在未來版本的 ECMAScript 計畫被導入。有兩種不同類型的解析:</p> + +<dl> + <dt>{{experimental_inline}} {{jsxref("Operators/Array_comprehensions", "[for (x of y) x]")}}</dt> + <dd>陣列解析。</dd> + <dt>{{experimental_inline}} {{jsxref("Operators/Generator_comprehensions", "(for (x of y) y)")}}</dt> + <dd>產生器解析。</dd> +</dl> + +<p>解析在許多程式語言中都存在,允許你快速地基於現存陣列產生新的陣列,例如:</p> + +<pre class="brush:js notranslate">[for (i of [ 1, 2, 3 ]) i*i ]; +// [ 1, 4, 9 ] + +var abc = [ 'A', 'B', 'C' ]; +[for (letters of abc) letters.toLowerCase()]; +// [ 'a', 'b', 'c' ]</pre> + +<h3 id="左側運算式">左側運算式</h3> + +<p>左側是指定值的對象。</p> + +<h4 id="new" name="new"><code>new</code></h4> + +<p>你可以使用 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> 運算子</a> 來建立一個使用者自定義物件或內建物件的實例。 用法如下:</p> + +<pre class="brush: js notranslate">var 物件名稱 = new 物件型態([參數1, 參數2, ..., 參數N]); +</pre> + +<h4 id="super">super</h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/super">super 關鍵字</a> 用於呼叫物件的父物件中的函式。 在使用 <a href="/en-US/docs/Web/JavaScript/Reference/Classes">類別</a> 來呼叫父類別的建構子時很實用,例如:</p> + +<pre class="syntaxbox notranslate">super([參數]); // 呼叫父物件的建構子. +super.父物件的函式([參數]); +</pre> + +<h4 id="展開運算子">展開運算子</h4> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">展開運算子</a>能將運算式展開於需要多個參數的地方 (如函式呼叫) 或是需要多個元素 (如陣列字串常數) 的地方。</p> + +<p><strong>範例:</strong> 現在你想要用已存在的一個陣列做為新的一個陣列的一部份,當字串常數不再可用而你必須使用指令式編程,也就是使用,一連串的 <code>push</code>, <code>splice</code>, <code>concat</code>,等等。 展開運算子能讓過程變得更加簡潔:</p> + +<pre class="brush: js notranslate">var parts = ['肩膀', '膝蓋']; +var lyrics = ['頭', ...parts, '和', '腳趾'];</pre> + +<p>相同的,展開運算子也適用於函式呼叫:</p> + +<pre class="brush: js notranslate">function f(x, y, z) { } +var args = [0, 1, 2]; +f(...參數);</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> diff --git a/files/zh-tw/web/javascript/guide/functions/index.html b/files/zh-tw/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..03866506d1 --- /dev/null +++ b/files/zh-tw/web/javascript/guide/functions/index.html @@ -0,0 +1,442 @@ +--- +title: 函式 +slug: Web/JavaScript/Guide/Functions +translation_of: Web/JavaScript/Guide/Functions +--- +<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</p> + +<p><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>是構成javascript的基本要素之一。<span id="result_box" lang="zh-TW"><span title="一个函数本身就是一段JavaScript程序——包含用于执行某一任务或计算的一系列语句。">一個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>本身就是一段JavaScript程序—<span id="result_box" lang="zh-TW"><span title="一个函数本身就是一段JavaScript程序——包含用于执行某一任务或计算的一系列语句。">包</span></span>含用於執行某一個任務或計算的語法。</span><span title="要使用某一个函数,你必需在想要调用这个函数的执行域的某处定义它。">要呼叫某一個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>之前,你必需先在這個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>欲執行的scope中定義它。</span></span></p> + +<h2 id="定義函式">定義<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span></h2> + +<p><span id="result_box" lang="zh-TW"><span title="一个函数的定义(也称为函数的声明)由一系列的函数关键词组成, 依次为: + + ">一個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>的定義由一系列的<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>關鍵詞組成, 依次為:</span></span></p> + +<ul> + <li><span title="一个函数的定义(也称为函数的声明)由一系列的函数关键词组成, 依次为: + + "> </span><span title="函数的名称。 + "><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>的名稱。</span></li> + <li><span lang="zh-TW"><span title="函数的名称。 + "> </span><span title="包围在括号()中,并由逗号区隔的一个函数引数(译注:实际参数)列表。 + ">包圍在括號()中,並由逗號區隔的一個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>參數列表。</span></span></li> + <li><span lang="zh-TW"><span title="包围在括号()中,并由逗号区隔的一个函数引数(译注:实际参数)列表。 + "> </span><span title="包围在花括号{}中,用于定义函数功能的一些JavaScript语句。">包圍在大括號{}中,用於定義<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>功能的一些JavaScript語句。</span></span></li> +</ul> + +<p> </p> + +<p><span class="short_text" id="result_box" lang="zh-TW"><span title="例如,以下的代码定义了一个名为square的简单函数:">例如,以下的程式碼定義了一個名為square的簡單<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>:</span></span></p> + +<div style="margin-right: 270px;"> +<pre class="brush: js">function square(number) { + return number * number; +} +</pre> +</div> + +<p><span id="result_box" lang="zh-TW"><span title="函数square使用了一个引数,叫作number。"><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>square有一個參數,叫作number。</span><span title="这个函数只有一个语句,它说明该函数会将函数的引数(即number)自乘后返回。">這個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>只有一行程式碼,它會回傳number自乘的結果。</span><span title="函数的return语句确定了函数的返回值。"><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>的 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/return" title="return"><code>return</code></a> 語法描述<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>的返回值。</span></span></p> + +<pre class="brush: js">return number * number; +</pre> + +<p><span id="result_box" lang="zh-TW"><span title="原始参数(比如一个具体的数字)被作为值传递给函数;值被传递给函数,但是如果被调用函数改变了这个参数的值,这样的改变不会影响到全局或调用的函数。">原始參數(例如一個數字)被作為值傳遞給<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>,如果呼叫的<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>改變了這個參數的值,不會影響到<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示"><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>外部的原始變數</span></span>。</span></span></p> + +<p><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">如果傳遞一個物件(例如 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="Array"><code>Array</code></a> 或自定義的其它物件)作為參數,而函式改變了這個物件的屬性,這樣的改變對函式外部是有作用的(因為是傳遞物件的位址),如下面的例子所示</span><span title=":">:</span></span></p> + +<pre class="brush: js">function myFunc(theObject) { + theObject.make = "Toyota"; +} + +var mycar = {make: "Honda", model: "Accord", year: 1998}, + x, + y; + +x = mycar.make; // x 的值為 "Honda" + +myFunc(mycar); +y = mycar.make; // y 的值為 "Toyota" + // (屬性 make 被 function 改變) +</pre> + +<p><span id="result_box" lang="zh-TW"><span title="请注意,重新给参数分配一个对象,并不会对函数的外部有任何影响,因为这样只是改变了参数的值,而不是改变了对象的一个属性值:">請注意,重新給參數指定一個對象(物件),並不會對函式的外部有任何影響,因為這樣只是改變了參數的值,而不是改變了對象的一個屬性值:</span></span></p> + +<pre class="brush: js">function myFunc(theObject) { + theObject = {make: "Ford", model: "Focus", year: 2006}; +} + +var mycar = {make: "Honda", model: "Accord", year: 1998}, + x, + y; + +x = mycar.make; // x 的值為 "Honda" + +myFunc(mycar); +y = mycar.make; // y 的值還是 "Honda" </pre> + +<p><span id="result_box" lang="zh-TW"><span title="当然上述函数定义都用的是语法语句,函数也同样可以由函数表达式产生。">儘管上述函式定義都是用的是陳述式,函式也同樣可以由函式表達式來定義。</span><span title="这样的函数可以是匿名的;它不必有名称。">這樣的函式可以是匿名的;它不必有名稱。</span><span title="例如,上面提到的函数square也可这样来定义:">例如,上面提到的函式square也可這樣來定義:</span></span></p> + +<pre class="brush: js" style="font-size: 14px;">var square = function(number) {return number * number}; +var x = square(4) //x 的值為 16</pre> + +<div class="almost_half_cell" id="gt-res-content"> +<div dir="ltr" style="zoom: 1;"><span id="result_box" lang="zh-TW"><span title="必要时,函数名称可与函数表达式同时存在,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中鉴别该函数:">必要時,函式名稱可與函式表達式同時存在,並且可以用於在函式內部代指其本身(遞迴):</span></span></div> + +<div dir="ltr" style="zoom: 1;"> </div> +</div> + +<pre class="brush: js" style="font-size: 14px;">var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)}; + +console.log(factorial(3)); +</pre> + +<p><span id="result_box" lang="zh-TW"><span title="函数表达式在将函数作为一个引数传递给其它函数时十分方便。">函式表達式在將函式作為一個參數傳遞給其它函式時十分方便。</span><span title="下面的例子演示了一个叫map的函数如何被定义,而后调用一个匿名函数作为其第一个参数:">下面的例子展示了一個叫map的函式如何被定義,而後呼叫一個匿名函式作為其第一個參數:</span></span></p> + +<pre class="brush: js" style="font-size: 14px;">function map(f,a) { + var result = [], // Create a new Array + i; + for (i = 0; i != a.length; i++) + result[i] = f(a[i]); + return result; +} +</pre> + +<p>下面的程式碼呼叫map<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>並將一個匿名<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>傳入作為第一個參數:</p> + +<pre class="brush: js" style="font-size: 14px;">map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]); +// 結果會回傳 [0, 1, 8, 125, 1000] +</pre> + +<p><span style="line-height: 1.572;">除了上述的定義方式以外,我們也可以透過 </span><a href="/en-US/docs/JavaScript/Guide/Predefined_Core_Objects#Function_Object" style="line-height: 1.572;" title="en-US/docs/JavaScript/Guide/Predefined Core Objects#Function Object"><code>Function</code> constructor</a><span style="line-height: 1.572;"> 來定義, 類似 </span><a href="/en-US/docs/JavaScript/Guide/Functions#eval_Function" style="line-height: 1.572;" title="en-US/docs/JavaScript/Guide/Functions#eval_Function"><code>eval()</code></a><span style="line-height: 1.572;">.</span></p> + +<h2 id="呼叫函式">呼叫函式</h2> + +<p><span id="result_box" lang="zh-TW"><span title="定义一个函数并不会自动的执行它。">定義一個<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>並不會自動的執行它。</span><span title="定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。">定義了<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>僅僅是賦予<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>以名稱並明確<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>被呼叫時該做些什麼。</span><span title="调用函数才会以给定的参数真正执行这些动作。">呼叫<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>才會以給定的參數真正執行這些動作。</span><span title="例如,一旦你定义了函数square,你可以如下这样调用它:">例如,一旦你定義了<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>square,你可以如下這樣呼叫它:</span></span></p> + +<pre class="brush: js">square(5); +</pre> + +<p><span class="short_text" id="result_box" lang="zh-TW"><span title="上述语句以引数(译注:即实际参数)5来调用函数。">上述程式碼把5傳遞給square<span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>。</span><span title="函数执行完它的语句会返回值25。"><span id="result_box" lang="zh-TW"><span title="如果你传递一个对象(即一个非实际值,例如矩阵或用户自定义的其它对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示">函式</span></span>執行完會回傳25。</span></span></p> + +<p>函式必須在呼叫區塊的可視範圍內,但函數也可以宣告在使用處的下面,如下列範例:</p> + +<pre>console.log(square(5)); +/* ... */ +function square(n){return n*n} +</pre> + +<p>The scope of a function is the function in which it is declared, or the entire program if it is declared at the top level. Note that this works only when defining the function using the above syntax (i.e. <code>function funcName(){}</code>). The code below will not work.</p> + +<pre class="brush: js">console.log(square(5)); +square = function (n) { + return n * n; +} +</pre> + +<p>The arguments of a function are not limited to strings and numbers. You can pass whole objects to a function, too. The <code>show_props</code> function (defined in <a href="/en-US/docs/JavaScript/Guide/Working_with_Objects#Objects_and_Properties" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects#Objects_and_Properties">Working with Objects</a>) is an example of a function that takes an object as an argument.</p> + +<p>A function can be recursive; that is, it can call itself. For example, here is a function that computes factorials recursively:</p> + +<pre class="brush: js">function factorial(n){ + if ((n == 0) || (n == 1)) + return 1; + else + return (n * factorial(n - 1)); +} +</pre> + +<p>You could then compute the factorials of one through five as follows:</p> + +<pre class="brush: js">var a, b, c, d, e; +a = factorial(1); // a gets the value 1 +b = factorial(2); // b gets the value 2 +c = factorial(3); // c gets the value 6 +d = factorial(4); // d gets the value 24 +e = factorial(5); // e gets the value 120 +</pre> + +<p>There are other ways to call functions. There are often cases where a function needs to be called dynamically, or the number of arguments to a function vary, or in which the context of the function call needs to be set to a specific object determined at runtime. It turns out that functions are, themselves, objects, and these objects in turn have methods (see the <a href="/en-US/docs/JavaScript/Guide/Obsolete_Pages/Predefined_Core_Objects/Function_Object" title="Function Object"><code>Function</code> object</a>). One of these, the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="apply"><code>apply()</code></a> method, can be used to achieve this goal.</p> + +<h2 class="deki-transform" id="Function_scope">Function scope</h2> + +<p>Variables defined inside a function cannot be accessed from anywhere outside the function, because the variable is defined only in the scope of the function. However, a function can access all variables and functions defined inside the scope in which it is defined. In other words, a function defined in the global scope can access all variables defined in the global scope. A function defined inside another function can also access all variables defined in it's parent function and any other variable to which the parent function has access.</p> + +<pre class="brush: js">// The following variables are defined in the global scope +var num1 = 20, + num2 = 3, + name = "Chamahk"; + +// This function is defined in the global scope +function multiply() { + return num1 * num2; +} + +multiply(); // Returns 60 + +// A nested function example +function getScore () { + var num1 = 2, + num2 = 3; + + function add() { + return name + " scored " + (num1 + num2); + } + + return add(); +} + +getScore(); // Returns "Chamahk scored 5" +</pre> + +<h2 id="閉包">閉包</h2> + +<p>閉包是 JavaScript 最強大的特性之一。JavaScript 允許巢狀函式(nesting of functions)並給予內部函式完全訪問(full access)所有變數、與外部函式定義的函式(還有所有外部函式內的變數與函式)不過,外部函式並不能訪問內部函式的變數與函式。這保障了內部函式的變數安全。另外,由於內部函式能訪問外部函式定義的變數與函式,將存活得比外部函式還久。A closure is created when the inner function is somehow made available to any scope outside the outer function.</p> + +<pre class="brush: js">var pet = function(name) { // The outer function defines a variable called "name" + var getName = function() { + return name; // The inner function has access to the "name" variable of the outer function + } + + return getName; // Return the inner function, thereby exposing it to outer scopes + }, + myPet = pet("Vivie"); + +myPet(); // Returns "Vivie" +</pre> + +<p>It can be much more complex than the code above. An object containing methods for manipulating the inner variables of the outer function can be returned.</p> + +<pre class="brush: js">var createPet = function(name) { + var sex; + + return { + setName: function(newName) { + name = newName; + }, + + getName: function() { + return name; + }, + + getSex: function() { + return sex; + }, + + setSex: function(newSex) { + if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) { + sex = newSex; + } + } + } +} + +var pet = createPet("Vivie"); +pet.getName(); // Vivie + +pet.setName("Oliver"); +pet.setSex("male"); +pet.getSex(); // male +pet.getName(); // Oliver +</pre> + +<p>In the codes above, the <code>name</code> variable of the outer function is accessible to the inner functions, and there is no other way to access the inner variables except through the inner functions. The inner variables of the inner function act as safe stores for the inner functions. They hold "persistent", yet secure, data for the inner functions to work with. The functions do not even have to be assigned to a variable, or have a name.</p> + +<pre class="brush: js">var getCode = (function(){ + var secureCode = "0]Eal(eh&2"; // A code we do not want outsiders to be able to modify... + + return function () { + return secureCode; + }; +})(); + +getCode(); // Returns the secret code +</pre> + +<p>There are, however, a number of pitfalls to watch out for when using closures. If an enclosed function defines a variable with the same name as the name of a variable in the outer scope, there is no way to refer to the variable in the outer scope again.</p> + +<pre class="brush: js">var createPet = function(name) { // Outer function defines a variable called "name" + return { + setName: function(name) { // Enclosed function also defines a variable called "name" + name = name; // ??? How do we access the "name" defined by the outer function ??? + } + } +} +</pre> + +<p>The magical <code>this</code> variable is very tricky in closures. They have to be used carefully, as what <code>this</code> refers to depends completely on where the function was called, rather than where it was defined. An excellent and elaborate article on closures can be found <a class="external" href="http://jibbering.com/faq/notes/closures/">here</a>.</p> + +<h2 id="Using_the_arguments_object">Using the arguments object</h2> + +<p>The arguments of a function are maintained in an array-like object. Within a function, you can address the arguments passed to it as follows:</p> + +<pre class="brush: js">arguments[i] +</pre> + +<p>where <code>i</code> is the ordinal number of the argument, starting at zero. So, the first argument passed to a function would be <code>arguments[0]</code>. The total number of arguments is indicated by <code>arguments.length</code>.</p> + +<p>Using the <code>arguments</code> object, you can call a function with more arguments than it is formally declared to accept. This is often useful if you don't know in advance how many arguments will be passed to the function. You can use <code>arguments.length</code> to determine the number of arguments actually passed to the function, and then access each argument using the <code>arguments</code> object.</p> + +<p>For example, consider a function that concatenates several strings. The only formal argument for the function is a string that specifies the characters that separate the items to concatenate. The function is defined as follows:</p> + +<pre class="brush: js">function myConcat(separator) { + var result = "", // initialize list + i; + // iterate through arguments + for (i = 1; i < arguments.length; i++) { + result += arguments[i] + separator; + } + return result; +} +</pre> + +<p>You can pass any number of arguments to this function, and it concatenates each argument into a string "list":</p> + +<pre class="brush: js">// returns "red, orange, blue, " +myConcat(", ", "red", "orange", "blue"); + +// returns "elephant; giraffe; lion; cheetah; " +myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); + +// returns "sage. basil. oregano. pepper. parsley. " +myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley"); +</pre> + +<p>Please note that the <code>arguments</code> variable is "array-like", but not an array. It is array-like in that is has a numbered index and a <code>length</code> property. However, it does not possess all of the array-manipulation methods.</p> + +<p>See the <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="en-US/docs/JavaScript/Reference/Global Objects/Function"><code>Function</code> object</a> in the JavaScript Reference for more information.</p> + +<h2 id="Predefined_functions">Predefined functions</h2> + +<p>JavaScript has several top-level predefined functions:</p> + +<ul> + <li>{{ web.link("#eval_function", "eval") }}</li> + <li>{{ web.link("#isFinite_function", "isFinite") }}</li> + <li>{{ web.link("#isNaN_function", "isNaN") }}</li> + <li>{{ web.link("#parseInt_and_parseFloat_functions", "parseInt and parseFloat") }}</li> + <li>{{ web.link("#Number_and_String_functions", "Number and String") }}</li> + <li>{{ web.link("#escape_and_unescape_functions", "encodeURI, decodeURI, encodeURIComponent, and decodeURIComponent") }} (all available with Javascript 1.5 and later).</li> +</ul> + +<p>The following sections introduce these functions. See the <a href="/en-US/docs/JavaScript/Reference" title="en-US/docs/JavaScript/Reference">JavaScript Reference</a> for detailed information on all of these functions.</p> + +<h3 id="eval_Function">eval Function</h3> + +<p>The <code>eval</code> function evaluates a string of JavaScript code without reference to a particular object. The syntax of <code>eval</code> is:</p> + +<pre class="brush: js">eval(expr); +</pre> + +<p>where <code>expr</code> is a string to be evaluated.</p> + +<p>If the string represents an expression, <code>eval</code> evaluates the expression. If the argument represents one or more JavaScript statements, eval performs the statements. The scope of <code>eval</code> code is identical to the scope of the calling code. Do not call <code>eval</code> to evaluate an arithmetic expression; JavaScript evaluates arithmetic expressions automatically.</p> + +<h3 id="isFinite_function">isFinite function</h3> + +<p>The <code>isFinite</code> function evaluates an argument to determine whether it is a finite number. The syntax of <code>isFinite</code> is:</p> + +<pre class="brush: js">isFinite(number); +</pre> + +<p>where <code>number</code> is the number to evaluate.</p> + +<p>If the argument is <code>NaN</code>, positive infinity or negative infinity, this method returns <code>false</code>, otherwise it returns <code>true</code>.</p> + +<p>The following code checks client input to determine whether it is a finite number.</p> + +<pre class="brush: js">if(isFinite(ClientInput)){ + /* take specific steps */ +} +</pre> + +<h3 id="isNaN_function">isNaN function</h3> + +<p>The <code>isNaN</code> function evaluates an argument to determine if it is "NaN" (not a number). The syntax of <code>isNaN</code> is:</p> + +<pre class="brush: js">isNaN(testValue); +</pre> + +<p>where <code>testValue</code> is the value you want to evaluate.</p> + +<p>The <code>parseFloat</code> and <code>parseInt</code> functions return "NaN" when they evaluate a value that is not a number. <code>isNaN</code> returns true if passed "NaN," and false otherwise.</p> + +<p>The following code evaluates <code>floatValue</code> to determine if it is a number and then calls a procedure accordingly:</p> + +<pre class="brush: js">var floatValue = parseFloat(toFloat); + +if (isNaN(floatValue)) { + notFloat(); +} else { + isFloat(); +} +</pre> + +<h3 id="parseInt_and_parseFloat_functions">parseInt and parseFloat functions</h3> + +<p>The two "parse" functions, <code>parseInt</code> and <code>parseFloat</code>, return a numeric value when given a string as an argument.</p> + +<p>The syntax of <code>parseFloat</code> is:</p> + +<pre class="brush: js">parseFloat(str); +</pre> + +<p>where <code>parseFloat</code> parses its argument, the string <code>str</code>, and attempts to return a floating-point number. If it encounters a character other than a sign (+ or -), a numeral (0-9), a decimal point, or an exponent, then it returns the value up to that point and ignores that character and all succeeding characters. If the first character cannot be converted to a number, it returns "NaN" (not a number).</p> + +<p>The syntax of <code>parseInt</code> is:</p> + +<pre class="brush: js">parseInt(str [, radix]); +</pre> + +<p><code>parseInt</code> parses its first argument, the string <code>str</code>, and attempts to return an integer of the specified <code>radix</code> (base), indicated by the second, optional argument, <code>radix</code>. For example, a radix of ten indicates to convert to a decimal number, eight octal, sixteen hexadecimal, and so on. For radixes above ten, the letters of the alphabet indicate numerals greater than nine. For example, for hexadecimal numbers (base 16), A through F are used.</p> + +<p>If <code>parseInt</code> encounters a character that is not a numeral in the specified radix, it ignores it and all succeeding characters and returns the integer value parsed up to that point. If the first character cannot be converted to a number in the specified radix, it returns "NaN." The <code>parseInt</code> function truncates the string to integer values.</p> + +<h3 id="Number_and_String_functions">Number and String functions</h3> + +<p>The <code>Number</code> and <code>String</code> functions let you convert an object to a number or a string. The syntax of these functions is:</p> + +<pre class="brush: js">var objRef; +objRef = Number(objRef); +objRef = String(objRef); +</pre> + +<p><code>objRef 是物件的參照</code>。 Number uses the valueOf() method of the object; String uses the toString() method of the object.</p> + +<p>下列範例將<code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Date" title="en-US/docs/JavaScript/Reference/Global Objects/Date"> 日期</a></code> 物件轉換為可讀字串。</p> + +<pre class="brush: js">var D = new Date(430054663215), + x; +x = String(D); // x 等於 "星期二 八月 18 04:37:43 GMT-0700 1983" +</pre> + +<p>下列範例將 <code><a class="internal" href="/en-US/docs/JavaScript/Reference/Global_Objects/String" title="en-US/docs/JavaScript/Reference/Global Objects/String">字串</a></code> 物件轉換為 <code><a class="internal" href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="en-US/docs/JavaScript/Reference/Global Objects/Number">數字</a></code> 物件。</p> + +<pre class="brush: js">var str = "12", + num; +num = Number(字串); +</pre> + +<p>使用 DOM 方法 <code>write()</code> 與 JavaScript <code>typeof</code> 運算子.</p> + +<pre class="brush: js">var str = "12", + num; +document.write(typeof str); +document.write("<br/>"); +num = Number(str); +document.write(typeof num); +</pre> + +<h3 id="escape_與_unescape_函式(JavaScript_1.5後去除)">escape 與 unescape 函式(JavaScript 1.5後去除)</h3> + +<p><code>escape</code> 與 <code>unescape</code> 對於非ASCII 字元無法處理。 在 JavaScript 1.5 之後改用 <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/encodeURI" title="en-US/docs/JavaScript/Reference/Global_Functions/encodeURI">encodeURI</a></code>, <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/decodeURI" title="en-US/docs/JavaScript/Reference/Global_Functions/decodeURI">decodeURI</a></code>, <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent" title="en-US/docs/JavaScript/Reference/Global_Functions/encodeURIComponent">encodeURIComponent</a></code>, 與 <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/decodeURIComponent" title="en-US/docs/JavaScript/Reference/Global_Functions/decodeURIComponent">decodeURIComponent</a></code>.</p> + +<p><code>escape</code> 與 <code>unescape</code> 用於編碼與解碼字串。 <code>escape</code> 函式回傳十六進位編碼。 <code>unescape</code> 函式會將十六進位的編碼轉換回 ASCII 字串。</p> + +<p>這些函式的語法是:</p> + +<pre class="brush: js">escape(字串); +unescape(字串); +</pre> + +<p>這些函式常被用於伺服器後端中處理姓名等資料。</p> diff --git a/files/zh-tw/web/javascript/guide/grammar_and_types/index.html b/files/zh-tw/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..ac059a7f24 --- /dev/null +++ b/files/zh-tw/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,697 @@ +--- +title: 語法與型別 +slug: Web/JavaScript/Guide/Grammar_and_types +tags: + - Guide + - JavaScript +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</div> + +<p class="summary">本章討論 JavaScript 的基本語法與基礎資料類型、包括變數、常數、字元常數</p> + +<h2 id="基礎知識">基礎知識</h2> + +<p>JavaScript 許多基本語法借鑒自 Java,C或是C++,但亦受 Awk、Perl 和 Python 的影響。</p> + +<p>JavaScript 是 Case-sensitive(區分大小寫)並使用 Unicode 編碼。舉例來說,Früh (德文的"early") 可以當作變數的名稱。</p> + +<pre><code>var Früh = "foobar";</code></pre> + +<p>但變數 früh 並不等於 Früh,因為大小寫對 JavaScript 是有區別的。</p> + +<p>在 JavaScript 中,每行指令被稱為 {{Glossary("Statement", "Statements")}},並用分號(;)分隔。空格、Tab 與換行符號皆被視為空白。JavaScript 的文件會從左到右進行掃描,並轉換成一系列的元素,像是令牌(Token)、控制字符(Control characters)、換行器(line terminators)、註解(Comments)或是空白(Withespace),ECMAScript 也定義了特定的保留字和字面值,並在每個沒有加分號的 Statement 自動加上分號。然而,推薦的作法還是在每個 Statement 的結尾自行加上分號,以防止一些潛在的副作用,如果需要更多資訊,可以參考<a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar">這篇</a>。</p> + +<h2 id="註解(Comments)">註解(Comments)</h2> + +<p>註解語法跟 C++ 和其他語言相同:</p> + +<pre class="brush: js">// a one line comment + +/* this is a longer, + multi-line comment + */ + +/* You can't, however, /* nest comments */ SyntaxError */</pre> + +<h2 id="宣告(Declarations)">宣告(Declarations)</h2> + +<p>JavaScript有三種宣告方式</p> + +<dl> + <dt>{{jsxref("Statements/var", "var")}}</dt> + <dd>宣告一個可隨意更改其內容的變數</dd> + <dt>{{jsxref("Statements/let", "let")}}</dt> + <dd>宣告一個可隨意更改其內容的區塊區域變數</dd> + <dt>{{jsxref("Statements/const", "const")}}</dt> + <dd>宣告一個只可讀取的不可變常數</dd> +</dl> + +<h3 id="變數(Variables)">變數(Variables)</h3> + +<p>變數(variable)是對值(value)的引用,變數的名稱被稱為 {{Glossary("Identifier", "identifiers")}} 需要遵從一定的規則。</p> + +<p>在 JavaScript 中,變數必須使用字母(letter)、下底線( _)、錢號($)作為開頭;後面的字員組成可以包含數字(0-9)。JavaScript 是區分大小寫(case secsitive)的,大寫字母('A' ~ 'Z')和小寫字母('a' ~ 'z')皆可使用且不相等。</p> + +<p>You can use most of ISO 8859-1 or Unicode letters such as å and ü in identifiers (for more details see <a href="https://mathiasbynens.be/notes/javascript-identifiers-es6">this blog post</a>). You can also use the <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals">Unicode escape sequences</a> as characters in identifiers.</p> + +<p>Some examples of legal names are <code>Number_hits</code>, <code>temp99</code>, <code>$credit</code>, and <code>_name</code>.</p> + +<h3 id="定義變數">定義變數</h3> + +<p>你可以透過三種方式來定義變數:</p> + +<ul> + <li>透過保留字 {{jsxref("Statements/var", "var")}} 來定義變數,舉例來說: <code>var x = 42</code>,這種方式可以用來定義區域以及全域變數。</li> + <li>直接指定一個值給該變數,例如:<code>x = 42</code>,這種方式只能定義全域變數,如果在方法外面使用該方法定義變數,嚴格模式裡會產生警告,該定義方式應該盡可能避免。</li> + <li>透過保留字 {{jsxref("Statements/let", "let")}},舉例來說:<code>let y = 13</code>,{{jsxref("Statements/let", "let")}} 可以用來定義區塊裡的區域變數。想瞭解更多,可以參考<a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">變數區域</a>的章節。</li> +</ul> + +<h3 id="變數取值">變數取值</h3> + +<p>變數可以透過 <code>var</code> 或是 <code>let</code> 來定義,如果尚未指定數值給該變數,那麼該變數的值會是 {{jsxref("undefined")}}。如果嘗試去存取未定義的變數,會跳出 {{jsxref("ReferenceError")}} 的例外。</p> + +<pre class="brush: js">var a; +console.log('The value of a is ' + a); // The value of a is undefined + +console.log('The value of b is ' + b); // The value of b is undefined +var b; + +console.log('The value of c is ' + c); // Uncaught ReferenceError: c is not defined + +let x; +console.log('The value of x is ' + x); // The value of x is undefined + +console.log('The value of y is ' + y); // Uncaught ReferenceError: y is not defined +let y; </pre> + +<p>你可以利用 <code>undefined</code> 來判斷該變數是否有值,在下面的程式碼的例子中,<code>input</code> 這個變數沒有賦值,<code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if</a> </code>判斷式會得到 <code>true</code> 的結果。</p> + +<pre class="brush: js">var input; +if (input === undefined) { + doThis(); +} else { + doThat(); +} +</pre> + +<p>被賦予 <code>undefined</code> 的變數,在被當做布林值的情境下都會被視為 <code>false</code>,以下面的例子來說,程式碼會執行 <code>myFunction</code>,因為 <code>myArray</code> 是 <code>undefined</code>:</p> + +<pre class="brush: js">var myArray = []; +if (!myArray[0]) myFunction(); +</pre> + +<p>被賦予 <code>undefined</code> 的變數,在和數值進行運算之後,會被轉成非數值(<code>NaN</code>):</p> + +<pre class="brush: js">var a; +a + 2; // Evaluates to NaN</pre> + +<p>當你對 {{jsxref("null")}} 進行運算,{{jsxref("null")}} 會自動轉換成數值 0,如果當做布林值運算,會被當成 <code>false</code>,舉例來說:</p> + +<pre class="brush: js">var n = null; +console.log(n * 32); // Will log 0 to the console +</pre> + +<h3 id="變數範圍">變數範圍</h3> + +<p>當我們在函式外宣告一個變數時,這個變數會是一個全域變數 (global variable), 因為在這份程式文件裡面的所有程式碼都可以使用到這個變數。但當我們只在函式內宣告變數時,這變數是區域變數 (local variable),因為變數只會在函式內被使用到。</p> + +<p><strong>請注意!!</strong> 在 ECMAScript 2015 以前的 JavaScript 版本裡,並沒有定義區塊描述 (<a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Block_statement">block statement</a>) 的變數有效範圍。更精確的說,之前版本所定義的變數,其特性相當於全域變數;不只在宣告的區塊或函數裡面有效 ,其變數值還會超出宣告區塊而影響到全部的描述碼。</p> + +<p>從下面例子來看,其輸出結果會是 5。雖然 x 是在 if { } 區塊裡面被宣告的,但卻因為有全域變數的特性,因此溢出大括號而成為後續描述碼的變數值。</p> + +<pre class="brush: js">if (true) { + var x = 5; +} +console.log(x); // x is 5 +</pre> + +<p>接著舉一個 ECMAScript 2015 之後的宣告範例。當使用了 <code>let</code> 這個區域變數宣告方式,變數 y 的有效範圍只有在 if { } 的範圍內,因此輸出結果是 ReferenceError。</p> + +<pre class="brush: js">if (true) { + let y = 5; +} +console.log(y); // ReferenceError: y is not defined (y沒有被定義) +</pre> + +<h3 id="變數提升">變數提升</h3> + +<p>在JavaScript 中另一件有關變數不常見的事, 是你可引用一個較晚宣告的變數並且不會有異常。這個概念被稱為「<strong>提升</strong>(<strong>hoisting</strong>)」;從意義上來說明,變數在 JavaScript 中是「被提升(hoisted)」或「被抬至(lifted)」到函式(function)或陳述式(statement)的頂部。<br> + 然而,被提升(hoisted)的變數將返回一個未定義的值(undefined)。所以即使你在使用或者引用這個變數之後才宣告和初始化它,它仍然會返回它是一個未定義的值(undefined)。</p> + +<pre class="brush: js">/** + * Example 1 + */ +console.log(x === undefined); // true +var x = 3; + +/** + * Example 2 + */ +// will return a value of undefined +var myvar = 'my value'; + +(function() { + console.log(myvar); // undefined + var myvar = 'local value'; +})(); +</pre> + +<p>上面的例子可以轉譯成如下相同的程式:</p> + +<pre class="brush: js">/** + * Example 1 + */ +var x; +console.log(x === undefined); // true +x = 3; + +/** + * Example 2 + */ +var myvar = 'my value'; + +(function() { + var myvar; + console.log(myvar); // undefined + myvar = 'local value'; +})(); +</pre> + +<p><br> + 由於提升(hoisting),全部在函數(function) 中的 var 陳述式應該盡可能地置放在接近函數(function)的頂部。這個最佳實踐增加了程式碼的清晰度。<br> + <br> + 在ECMAScript 2015 中,let(const)不會將變數提升到區塊(block)的頂部。但是,在變數宣告之前就引用塊中的變數,會導致 {{jsxref("ReferenceError")}}。變數從區塊(block)的開始到宣告被處理之前,就處於「暫時無效(temporal dead zone)」。</p> + +<pre class="brush: js">console.log(x); // ReferenceError +let x = 3;</pre> + +<h3 id="函式提升">函式提升</h3> + +<p>針對函式來說,只有函式宣告式(function declaration)提昇到頂部,但函式表示式(function exprssion) 不被提昇至頂部。</p> + +<pre class="brush: js">/* Function declaration */ + +foo(); // "bar" + +function foo() { + console.log('bar'); +} + + +/* Function expression */ + +baz(); // TypeError: baz is not a function + +var baz = function() { + console.log('bar2'); +}; +</pre> + +<h3 id="全域變數_Global_variables">全域變數 (Global variables)</h3> + +<p>全域變數事實上是全域物件的屬性值。在網頁中的全域物件是 {{domxref("window")}},因此你可使用 <code>window.<em>variable</em></code> 的語法來設定及存取全域變數。</p> + +<p>Consequently, 你可以指定 window 或 frame 物件的名稱來存取在另一個在 window 物件或 frame 物件所宣告的全域變數。例如,如果在一個文檔中已宣告一個稱為 <code>phoneNumber</code> 的變數,你可以在 iframe 中使用 <code>parent.phoneNumber</code> 來存取該變數</p> + +<h3 id="常數_Constants">常數 (Constants)</h3> + +<p>你可用 {{jsxref("Statements/const", "const")}} 關鍵字來建立一個唯讀、有名稱的常數。 常數識別子的命名語法與變數識別子的命名語法是一樣的: 必須由一個英文字母,底線或錢符號($)開始,之後可包含英文字母,數字及底線字元。</p> + +<pre class="brush: js">const PI = 3.14; +</pre> + +<p>當程式執行時,無法再透過賦值或重新宣告來改變常數已設定的值。常數必須被初始化。</p> + +<p>The scope rules for constants are the same as those for <code>let</code> block-scope variables. If the <code>const</code> keyword is omitted, the identifier is assumed to represent a variable.</p> + +<p>你不能在同一個局部範圍內使用與其它函式或變數相同的名稱來宣告變數。例如:</p> + +<pre class="brush: js">// THIS WILL CAUSE AN ERROR +function f() {}; +const f = 5; + +// THIS WILL CAUSE AN ERROR ALSO +function f() { + const g = 5; + var g; + + //statements +} +</pre> + +<p>但是常數物件內的物件屬性並不受到保護,因此以下陳述式可以正常執行。</p> + +<pre class="brush: js">const MY_OBJECT = {'key': 'value'}; +MY_OBJECT.key = 'otherValue';</pre> + +<h2 id="資料結構及型別">資料結構及型別</h2> + +<h3 id="資料型別_Data_types">資料型別 (Data types)</h3> + +<p>最新 ECMAScript 標準定義以下七種資料型別:</p> + +<ul> + <li>六種基本({{Glossary("Primitive", "primitives")}})資料型別 : + <ul> + <li>{{Glossary("Boolean")}}. <code>true</code> and <code>false</code>.</li> + <li>{{Glossary("null")}}. A special keyword denoting a null value. Because JavaScript is case-sensitive, <code>null</code> is not the same as <code>Null</code>, <code>NULL</code>, or any other variant.</li> + <li>{{Glossary("undefined")}}. A top-level property whose value is undefined.</li> + <li>{{Glossary("Number")}}. <code>42</code> or <code>3.14159</code>.</li> + <li>{{Glossary("String")}}. "Howdy"</li> + <li>{{Glossary("Symbol")}} (new in ECMAScript 2015). A data type whose instances are unique and immutable.</li> + </ul> + </li> + <li>and {{Glossary("Object")}}</li> +</ul> + +<p>儘管這些變數關聯性很小, 他們可以讓你在你的應用程式中, 產生出有意義的函數. </p> + +<p><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object">物件</a>與 <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="en-US/docs/JavaScript/Reference/Global Objects/Function">函數</a> 在語言中是其它的基本元素. 你可以把物件想成是一個被命名過且用來裝數值的容器,以及函數則為你的應用程式所執行的步驟. </p> + +<h3 id="資料型別轉換">資料型別轉換</h3> + +<p>JavaScript 是一個動態型別的語言,這意味著你不需要在宣告變數時定義它的資料型別,程式執行時會自動轉換,你可以用下面方式宣告變數:</p> + +<div style="overflow: hidden;"> +<pre class="brush: js">var answer = 42; +</pre> +</div> + +<p>你可以指派字串在同個變數中,例如:</p> + +<div style="overflow: hidden;"> +<pre class="brush: js">answer = "Thanks for all the fish..."; +</pre> +</div> + +<p>由於 Javascript 是一個動態型別的語言,因此這樣的宣告方式不會導致錯誤。</p> + +<p>在該陳述式中,它調用了字串和數字,並使用 + 進行運算,JavaScript 會自動把數字轉換成字串,例如:</p> + +<pre class="brush: js">x = "The answer is " + 42 // "The answer is 42" +y = 42 + " is the answer" // "42 is the answer" +</pre> + +<p>在該陳述式中,它調用了其它運算子,JavaScript 就不會將數字轉換成字串,例如:</p> + +<pre class="brush: js">"37" - 7 // 30 +"37" + 7 // "377" +</pre> + +<h3 id="字串轉數值">字串轉數值</h3> + +<p>當代表數字的值以字串形式存在記憶體中,有些方法可用來將這種字串轉換成整數或浮點數。 </p> + +<ul> + <li id="parseInt()_and_parseFloat()">{{jsxref("parseInt", "parseInt()")}}</li> + <li>{{jsxref("parseFloat", "parseFloat()")}}</li> +</ul> + +<p><code>parseInt</code> 只會返回整數,因此減少了對小數的使用。此外,parseInt 的最佳實務是始終包含基數參數。基數參數用於指定使用的數值系統。</p> + +<p>另一個將字串轉成數字是使用單元 <code>+</code> (unary plus) 運算子:</p> + +<pre class="brush: js">'1.1' + '1.1' = '1.11.1' +(+'1.1') + (+'1.1') = 2.2 +// 注意: 括號是為了易於閱讀,並不是必須的.</pre> + +<h2 id="字面值(Literals)">字面值(Literals)</h2> + +<p>您能使用字面值來表示JavaScript中的值。這些是您在腳本中實際提供的固定值,而不是變量。本節描述以下類型的字面值:</p> + +<ul> + <li>{{anch("Array literals")}}</li> + <li>{{anch("Boolean literals")}}</li> + <li>{{anch("Floating-point literals")}}</li> + <li>{{anch("Integers")}}</li> + <li>{{anch("Object literals")}}</li> + <li>{{anch("RegExp literals")}}</li> + <li>{{anch("String literals")}}</li> +</ul> + +<h3 id="陣列字面值_Array_literals">陣列字面值 (Array literals)</h3> + +<p>陣列字面值是零或多個表達式的列表,每個表達式代表一個數組元素,並用方括號([])括起來。使用陣列字面值創建陣列時,將使用指定的值作為其元素對其進行初始化,並將其長度設置為指定的參數值。</p> + +<p>以下範例創建了陣列 <code>coffees</code> ,長度為 3 並包含三個元素:</p> + +<pre class="brush: js">var coffees = ['French Roast', 'Colombian', 'Kona']; +</pre> + +<div class="note"> +<p><strong>Note :</strong> An array literal is a type of object initializer. See <a href="/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Using_object_initializers">Using Object Initializers</a>.</p> +</div> + +<p>If an array is created using a literal in a top-level script, JavaScript interprets the array each time it evaluates the expression containing the array literal. In addition, a literal used in a function is created each time the function is called.</p> + +<p>Array literals are also <code>Array</code> objects. See {{jsxref("Array")}} and <a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> for details on <code>Array</code> objects.</p> + +<h4 id="Extra_commas_in_array_literals">Extra commas in array literals</h4> + +<p>You do not have to specify all elements in an array literal. If you put two commas in a row, the array is created with <code>undefined</code> for the unspecified elements. The following example creates the <code>fish</code> array:</p> + +<pre class="brush: js">var fish = ['Lion', , 'Angel']; +</pre> + +<p>This array has two elements with values and one empty element (<code>fish[0]</code> is "Lion", <code>fish[1]</code> is <code>undefined</code>, and <code>fish[2]</code> is "Angel").</p> + +<p>If you include a trailing comma at the end of the list of elements, the comma is ignored. In the following example, the length of the array is three. There is no <code>myList[3]</code>. All other commas in the list indicate a new element.</p> + +<div class="note"> +<p><strong>Note :</strong> Trailing commas can create errors in older browser versions and it is a best practice to remove them.</p> +</div> + +<pre class="brush: js">var myList = ['home', , 'school', ]; +</pre> + +<p>In the following example, the length of the array is four, and <code>myList[0]</code> and <code>myList[2]</code> are missing.</p> + +<pre class="brush: js">var myList = [ ,'home', , 'school']; +</pre> + +<p>In the following example, the length of the array is four, and <code>myList[1]</code> and <code>myList[3]</code> are missing. <strong>Only the last comma is ignored.</strong></p> + +<pre class="brush: js">var myList = ['home', , 'school', , ]; +</pre> + +<p>Understanding the behavior of extra commas is important to understanding JavaScript as a language, however when writing your own code: explicitly declaring the missing elements as <code>undefined</code> will increase your code's clarity and maintainability.</p> + +<h3 id="布林字面值_Boolean_literals">布林字面值 (Boolean literals)</h3> + +<p>布林型別有兩種字面值: <code>true</code> 跟 <code>false</code>.</p> + +<p>Do not confuse the primitive Boolean values <code>true</code> and <code>false</code> with the true and false values of the Boolean object. The Boolean object is a wrapper around the primitive Boolean data type. See {{jsxref("Boolean")}} for more information.</p> + +<h3 id="整數字面值_Numerical_literals">整數字面值 (Numerical literals)</h3> + +<p>整數能表示為「十進制」、「十六進制」、「八進制」、「二進制」</p> + +<ul> + <li>十進制整數字面值由「『不帶前導 0』的整數序列」組成</li> + <li>八進制整數字面值由「『前導 0』」或『前導 0o』或『前導 0O』的整數序列」組成。八進制整數只能包含數字0-7</li> + <li>十六進制整數字面值由「『前導 0x』」或『前導 0X』的整數序列」組成。十六進制整數只能包含數字 0-9 、字母 A-F 和 a-f</li> + <li>二進制整數字面值由「『前導 0b』」或『前導 0B』的整數序列」組成。二進制整數只能包含數字 0 跟 1</li> +</ul> + +<p>整數字面值範例如下:</p> + +<pre class="eval">0, 117 and -345 (decimal, base 10) +015, 0001 and -0o77 (octal, base 8) +0x1123, 0x00111 and -0xF1A7 (hexadecimal, "hex" or base 16) +0b11, 0b0011 and -0b11 (binary, base 2) +</pre> + +<p>更多資訊請參閱 <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Numeric_literals">Numeric literals in the Lexical grammar reference</a>.</p> + +<h3 id="浮點數字面值_Floating-point_literals">浮點數字面值 (Floating-point literals)</h3> + +<p>浮點數字面值能包含以下部分:</p> + +<ul> + <li>整數部分 (十進位,可帶符號 "+" 或 "-" 於整數前)</li> + <li>小數點 "."</li> + <li>小數部分 (另一個十進位整數)</li> + <li>指數部分</li> +</ul> + +<p>指數部分由「"e" 或 "E" 後面跟整數」所組成,可帶符號 "+" 或 "-" 於整數前。浮點數字面值至少由「一位數字」與「一個小數點 "e" (或 "E")」組成。</p> + +<p>簡言之,於法如下:</p> + +<pre class="eval">[(+|-)][digits][.digits][(E|e)[(+|-)]digits] +</pre> + +<p>舉個例子:</p> + +<pre class="eval">3.1415926 +-.123456789 +-3.1E+12 +.1e-23 +</pre> + +<h3 id="物件字面值_Object_literals">物件字面值 (Object literals)</h3> + +<p>物件字面值是用大括號({})括起來的零或多對鍵值對的列表。因為 "{" 將被解譯為區塊(block)的開頭,因此你不應在陳述句開頭使用物件字面值,這將導致錯誤或不預期的行為。</p> + +<p>以下是物件字面值的範例。<code>car</code> 物件包含三個屬性:</p> + +<ul> + <li>第一個屬性 <code>myCar</code> 賦值為字串 '<code>Saturn</code>'</li> + <li>第二個屬性 <code>getCar</code> 賦值為「調用函數<code>carTypes('Honda')</code>」的結果</li> + <li>第三個屬性 <code>special </code>使用現有變量 <code>sales</code> 賦值</li> +</ul> + +<pre class="brush: js">var sales = 'Toyota'; + +function carTypes(name) { + if (name === 'Honda') { + return name; + } else { + return "Sorry, we don't sell " + name + "."; + } +} + +var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales }; + +console.log(car.myCar); // Saturn +console.log(car.getCar); // Honda +console.log(car.special); // Toyota +</pre> + +<p>此外,您可以使用數字或字串字面值作為屬性名,也可將物件嵌套在另一個物件中。如下範例:</p> + +<pre class="brush: js">var car = { manyCars: {a: 'Saab', 'b': 'Jeep'}, 7: 'Mazda' }; + +console.log(car.manyCars.b); // Jeep +console.log(car[7]); // Mazda +</pre> + +<p>物件屬性名可以是任何字串,包括空字串。如果屬性名不是有效的 JavaScript {{Glossary("Identifier","識別字")}} 或數字,則必須將其用引號引起來。無效的屬性名稱也不能作為點 (<code>.</code>) 屬性訪問,但是可以使用類似數組的符號("<code>[]</code>")進行訪問和設置。</p> + +<pre class="brush: js">var unusualPropertyNames = { + '': 'An empty string', + '!': 'Bang!' +} +console.log(unusualPropertyNames.''); // SyntaxError: Unexpected string +console.log(unusualPropertyNames['']); // An empty string +console.log(unusualPropertyNames.!); // SyntaxError: Unexpected token ! +console.log(unusualPropertyNames['!']); // Bang!</pre> + +<h4 id="Enhanced_Object_literals">Enhanced Object literals</h4> + +<p>In ES2015, object literals are extended to support setting the prototype at construction, shorthand for <code>foo: foo</code> assignments, defining methods, making super calls, and computing property names with expressions. Together, these also bring object literals and class declarations closer together, and let object-based design benefit from some of the same conveniences.</p> + +<pre class="brush: js">var obj = { + // __proto__ + __proto__: theProtoObj, + // Shorthand for ‘handler: handler’ + handler, + // Methods + toString() { + // Super calls + return 'd ' + super.toString(); + }, + // Computed (dynamic) property names + [ 'prop_' + (() => 42)() ]: 42 +};</pre> + +<p>Please note:</p> + +<pre class="brush: js">var foo = {a: 'alpha', 2: 'two'}; +console.log(foo.a); // alpha +console.log(foo[2]); // two +//console.log(foo.2); // Error: missing ) after argument list +//console.log(foo[a]); // Error: a is not defined +console.log(foo['a']); // alpha +console.log(foo['2']); // two +</pre> + +<h3 id="正規表達式字面值_RegExp_literals">正規表達式字面值 (RegExp literals)</h3> + +<p>正則表達式字面值是包含在斜杠間的樣式。以下是正則表達式文字的範例。</p> + +<pre class="brush: js">var re = /ab+c/;</pre> + +<h3 id="字串字面值_String_literals">字串字面值 (String literals)</h3> + +<p>字串字面值是用雙引號(“)或單引號(')包住的零或多個字元。字串必須用同類的引號定界;也就是「兩個單引號」或「兩個雙引號」。以下是字串字面值的範例:</p> + +<pre class="brush: js">'foo' +"bar" +'1234' +'one line \n another line' +"John's cat" +</pre> + +<p>你可以在字串字面值上調用 String 物件的任何方法 - JavaScript 將自動轉換字串字面值為臨時 String 物件並調用該方法,然後丟棄該臨時 String 物件。您還可以將 String.length 屬性與字串字面值一起使用:</p> + +<pre class="brush: js">console.log("John's cat".length) +// Will print the number of symbols in the string including whitespace. +// In this case, 10. +</pre> + +<p>In ES2015, template literals are also available. Template literals are enclosed by the back-tick (` `) (<a class="external external-icon" href="http://en.wikipedia.org/wiki/Grave_accent" rel="noopener">grave accent</a>) character instead of double or single quotes. Template strings provide syntactic sugar for constructing strings. This is similar to string interpolation features in Perl, Python and more. Optionally, a tag can be added to allow the string construction to be customized, avoiding injection attacks or constructing higher level data structures from string contents.</p> + +<pre class="brush: js">// Basic literal string creation +`In JavaScript '\n' is a line-feed.` + +// Multiline strings +`In JavaScript template strings can run + over multiple lines, but double and single + quoted strings cannot.` + +// String interpolation +var name = 'Bob', time = 'today'; +`Hello ${name}, how are you ${time}?` + +// Construct an HTTP request prefix is used to interpret the replacements and construction +POST`http://foo.org/bar?a=${a}&b=${b} + Content-Type: application/json + X-Credentials: ${credentials} + { "foo": ${foo}, + "bar": ${bar}}`(myOnReadyStateChangeHandler);</pre> + +<p>You should use string literals unless you specifically need to use a String object. See {{jsxref("String")}} for details on <code>String</code> objects.</p> + +<h4 id="字串裡的特殊字元">字串裡的特殊字元</h4> + +<p>除了普通字元,字串也能包含特殊字元,範例如下:</p> + +<pre class="brush: js">'one line \n another line' +</pre> + +<p>下表列出了可以在 JavaScript 字串中使用的特殊字元。</p> + +<table class="standard-table"> + <caption>表格: JavaScript 特殊字元</caption> + <thead> + <tr> + <th scope="col">字元</th> + <th scope="col">意涵</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>\0</code></td> + <td>Null Byte</td> + </tr> + <tr> + <td><code>\b</code></td> + <td>退格 (Backspace)</td> + </tr> + <tr> + <td><code>\f</code></td> + <td>Form feed</td> + </tr> + <tr> + <td><code>\n</code></td> + <td>換行 (New line)</td> + </tr> + <tr> + <td><code>\r</code></td> + <td>回車 (Carriage return)</td> + </tr> + <tr> + <td><code>\t</code></td> + <td>跳格 (Tab)</td> + </tr> + <tr> + <td><code>\v</code></td> + <td>Vertical tab</td> + </tr> + <tr> + <td><code>\'</code></td> + <td>Apostrophe or single quote</td> + </tr> + <tr> + <td><code>\"</code></td> + <td>Double quote</td> + </tr> + <tr> + <td><code>\\</code></td> + <td>Backslash character</td> + </tr> + <tr> + <td><code>\<em>XXX</em></code></td> + <td>The character with the Latin-1 encoding specified by up to three octal digits <em>XXX</em> between 0 and 377. For example, \251 is the octal sequence for the copyright symbol.</td> + </tr> + <tr> + </tr> + <tr> + <td><code>\x<em>XX</em></code></td> + <td>The character with the Latin-1 encoding specified by the two hexadecimal digits <em>XX</em> between 00 and FF. For example, \xA9 is the hexadecimal sequence for the copyright symbol.</td> + </tr> + <tr> + </tr> + <tr> + <td><code>\u<em>XXXX</em></code></td> + <td>The Unicode character specified by the four hexadecimal digits <em>XXXX</em>. For example, \u00A9 is the Unicode sequence for the copyright symbol. See <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals">Unicode escape sequences</a>.</td> + </tr> + <tr> + <td><code>\u<em>{XXXXX}</em></code></td> + <td>Unicode code point escapes. For example, \u{2F804} is the same as the simple Unicode escapes \uD87E\uDC04.</td> + </tr> + </tbody> +</table> + +<h4 id="Escaping_characters">Escaping characters</h4> + +<p>For characters not listed in the table, a preceding backslash is ignored, but this usage is deprecated and should be avoided.</p> + +<p>You can insert a quotation mark inside a string by preceding it with a backslash. This is known as <em>escaping</em> the quotation mark. For example:</p> + +<pre class="brush: js">var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service."; +console.log(quote); +</pre> + +<p>The result of this would be:</p> + +<pre class="eval">He read "The Cremation of Sam McGee" by R.W. Service. +</pre> + +<p>To include a literal backslash inside a string, you must escape the backslash character. For example, to assign the file path <code>c:\temp</code> to a string, use the following:</p> + +<pre class="brush: js">var home = 'c:\\temp'; +</pre> + +<p>You can also escape line breaks by preceding them with backslash. The backslash and line break are both removed from the value of the string.</p> + +<pre class="brush: js">var str = 'this string \ +is broken \ +across multiple \ +lines.' +console.log(str); // this string is broken across multiplelines. +</pre> + +<p>Although JavaScript does not have "heredoc" syntax, you can get close by adding a line break escape and an escaped line break at the end of each line:</p> + +<pre class="brush: js">var poem = +'Roses are red,\n\ +Violets are blue.\n\ +Sugar is sweet,\n\ +and so is foo.' +</pre> + +<p>ECMAScript 2015 introduces a new type of literal, namely <a href="/en-US/docs/Web/JavaScript/Reference/template_strings"><strong>template literals</strong></a>. This allows for many new features including multiline strings!</p> + +<pre class="brush: js" dir="rtl">var poem = +`Roses are red, +Violets are blue. +Sugar is sweet, +and so is foo.` </pre> + +<h2 id="More_information">More information</h2> + +<p>This chapter focuses on basic syntax for declarations and types. To learn more about JavaScript's language constructs, see also the following chapters in this guide:</p> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">Control flow and error handling</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Functions">Functions</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a></li> +</ul> + +<p>In the next chapter, we will have a look at control flow constructs and error handling.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</p> diff --git a/files/zh-tw/web/javascript/guide/index.html b/files/zh-tw/web/javascript/guide/index.html new file mode 100644 index 0000000000..769f57c55e --- /dev/null +++ b/files/zh-tw/web/javascript/guide/index.html @@ -0,0 +1,116 @@ +--- +title: JavaScript 指南 +slug: Web/JavaScript/Guide +translation_of: Web/JavaScript/Guide +--- +<div>{{jsSidebar("JavaScript Guide")}}</div> + +<p class="summary">JavaScript 指南會讓您了解如何使用 <a href="/zh-TW/docs/Web/JavaScript">JavaScript</a> 並給您這個語言的概觀。若您需要語言功能詳細資訊請參考 <a href="/zh-TW/docs/Web/JavaScript/Reference">JavaScript 參考文件</a>。</p> + +<h2 id="章節">章節</h2> + +<p>本指南區分成以下數個章節:</p> + +<ul class="card-grid"> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction">簡介</a></span> + + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#Where_to_find_JavaScript_information">關於本指南</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#What_is_JavaScript">關於 JavaScript</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_Java">JavaScript 與 Java</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_the_ECMAScript_Specification">ECMAScript</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#Getting_started_with_JavaScript">工具</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Introduction#Hello_world">Hello World</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types">語法與型別</a></span> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#Basics">基礎語法 & 註解</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#Declarations">宣告</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#Variable_scope">變數範圍</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#Variable_hoisting">變數提升(Hoisting)</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#Data_structures_and_types">資料結構與型態</a><br> + <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types#%E5%AD%97%E9%9D%A2%E5%80%BC%EF%BC%88Literals%EF%BC%89">字面值</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">流程控制與錯誤處理</a></span> + <p><code><a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement">if...else</a></code><br> + <code><a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#switch_statement">switch</a></code><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Exception_handling_statements"><code>try</code>/<code>catch</code>/<code>throw</code></a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Utilizing_Error_objects">Error 物件</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Promises">Promises</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration">迴圈與迭代</a></span> + <p><code><a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#for_statement">for</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#while_statement">while</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#do...while_statement">do...while</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#break_statement">break</a>/<a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#continue_statement">continue</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#for...in_statement">for..in</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Loops_and_iteration#for...of_statement">for..of</a></code></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Functions">函數</a></span> + + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Defining_functions">定義函數</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Calling_functions">呼叫函數</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Function_scope">函數範圍</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Closures">閉包(Closure)</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Using_the_arguments_object">參數值</a> & <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Function_parameters">參數</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Functions#Arrow_functions">箭頭函數</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators">運算式與運算子</a></span> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment_operators">賦值</a> & <a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Comparison_operators">比較</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic_operators">算數運算子</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators">位元</a> & <a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical_operators">邏輯運算子</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#Conditional_(ternary)_operator">條件(三元)運算子</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Numbers_and_dates">數字與日期</a></span><a href="/zh-TW/docs/Web/JavaScript/Guide/Numbers_and_dates#Numbers">數字書寫法</a> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Numbers_and_dates#Number_object"><code>Number</code> 物件</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Numbers_and_dates#Math_object"><code>Math</code> 物件</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Numbers_and_dates#Date_object"><code>Date</code> 物件</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Text_formatting">文字格式</a></span> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Text_formatting#String_literals">字串書寫法</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Text_formatting#String_objects"><code>String</code> 物件</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Text_formatting#Multi-line_template_literals">模板書寫法</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Text_formatting#Internationalization">國際化</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions">正規表示法</a></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Indexed_collections">具索引的集合</a></span> + + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Indexed_collections#Array_object">陣列</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Indexed_collections#Typed_Arrays">型態化陣列</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Keyed_collections">具鍵值的集合</a></span> + <p><code><a href="/zh-TW/docs/Web/JavaScript/Guide/Keyed_collections#Map_object">Map</a></code><br> + <code><a href="/zh-TW/docs/Web/JavaScript/Guide/Keyed_collections#WeakMap_object">WeakMap</a></code><br> + <code><a href="/zh-TW/docs/Web/JavaScript/Guide/Keyed_collections#Set_object">Set</a></code><br> + <code><a href="/zh-TW/docs/Web/JavaScript/Guide/Keyed_collections#WeakSet_object">WeakSet</a></code></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects">使用物件</a></span> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties">物件與屬性</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects#Creating_new_objects">建立物件</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_methods">定義方法</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters">取值器與設值器</a></p> + </li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">深入了解物件模型</a></span> + <p><a href="/zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Class-based_vs._prototype-based_languages">以原形(Prototype)為基礎的 OOP</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Creating_the_hierarchy">建立物件層級</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Property_inheritance_revisited">繼承</a></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Iterators_and_Generators">迭代器與產生器</a></span><a href="/zh-TW/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterators">迭代器(Iterator)</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables">可迭代型態(Iterable)</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generators">產生器(Generator)</a></li> + <li><span><a href="/zh-TW/docs/Web/JavaScript/Guide/Meta_programming">Meta 程式設計</a></span> + <p><code><a href="/zh-TW/docs/Web/JavaScript/Guide/Meta_programming#Proxies">Proxy</a></code><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Meta_programming#Handlers_and_traps">Handler 與 Trap</a><br> + <a href="/zh-TW/docs/Web/JavaScript/Guide/Meta_programming#Revocable_Proxy">Revocable Proxy</a><br> + <code><a href="/zh-TW/docs/Web/JavaScript/Guide/Meta_programming#Reflection">Reflect</a></code></p> + </li> +</ul> + +<p>{{Next("Web/JavaScript/Guide/Introduction")}}</p> diff --git a/files/zh-tw/web/javascript/guide/indexed_collections/index.html b/files/zh-tw/web/javascript/guide/indexed_collections/index.html new file mode 100644 index 0000000000..b34c419252 --- /dev/null +++ b/files/zh-tw/web/javascript/guide/indexed_collections/index.html @@ -0,0 +1,450 @@ +--- +title: 索引集合 +slug: Web/JavaScript/Guide/Indexed_collections +translation_of: Web/JavaScript/Guide/Indexed_collections +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</div> + +<p class="summary">This chapter introduces collections of data which are ordered by an index value. This includes arrays and array-like constructs such as {{jsxref("Array")}} objects and {{jsxref("TypedArray")}} objects.</p> + +<h2 id="Array_object"><code>Array</code> object</h2> + +<p>An <em>array</em> is an ordered set of values that you refer to with a name and an index. For example, you could have an array called <code>emp</code> that contains employees' names indexed by their numerical employee number. So <code>emp[1]</code> would be employee number one, <code>emp[2]</code> employee number two, and so on.</p> + +<p>JavaScript does not have an explicit array data type. However, you can use the predefined <code>Array</code> object and its methods to work with arrays in your applications. The <code>Array</code> object has methods for manipulating arrays in various ways, such as joining, reversing, and sorting them. It has a property for determining the array length and other properties for use with regular expressions.</p> + +<h3 id="Creating_an_array">Creating an array</h3> + +<p>The following statements create equivalent arrays:</p> + +<pre class="brush: js">var arr = new Array(element0, element1, ..., elementN); +var arr = Array(element0, element1, ..., elementN); +var arr = [element0, element1, ..., elementN]; +</pre> + +<p><code>element0, element1, ..., elementN</code> is a list of values for the array's elements. When these values are specified, the array is initialized with them as the array's elements. The array's <code>length</code> property is set to the number of arguments.</p> + +<p>The bracket syntax is called an "array literal" or "array initializer." It's shorter than other forms of array creation, and so is generally preferred. See <a href="/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Array_literals">Array literals</a> for details.</p> + +<p>To create an array with non-zero length, but without any items, either of the following can be used:</p> + +<pre class="brush: js">var arr = new Array(arrayLength); +var arr = Array(arrayLength); + +// This has exactly the same effect +var arr = []; +arr.length = arrayLength; +</pre> + +<div class="note"> +<p><strong>Note :</strong> in the above code, <code>arrayLength</code> must be a <code>Number</code>. Otherwise, an array with a single element (the provided value) will be created. Calling <code>arr.length</code> will return <code>arrayLength</code>, but the array actually contains empty (undefined) elements. Running a {{jsxref("Statements/for...in","for...in")}} loop on the array will return none of the array's elements.</p> +</div> + +<p>In addition to a newly defined variable as shown above, arrays can also be assigned as a property of a new or an existing object:</p> + +<pre class="brush: js">var obj = {}; +// ... +obj.prop = [element0, element1, ..., elementN]; + +// OR +var obj = {prop: [element0, element1, ...., elementN]}; +</pre> + +<p>If you wish to initialize an array with a single element, and the element happens to be a <code>Number</code>, you must use the bracket syntax. When a single <code>Number</code> value is passed to the Array() constructor or function, it is interpreted as an <code>arrayLength</code>, not as a single element.</p> + +<pre class="brush: js">var arr = [42]; // Creates an array with only one element: + // the number 42. + +var arr = Array(42); // Creates an array with no elements + // and arr.length set to 42; this is + // equivalent to: +var arr = []; +arr.length = 42; +</pre> + +<p>Calling <code>Array(N)</code> results in a <code>RangeError</code>, if <code>N</code> is a non-whole number whose fractional portion is non-zero. The following example illustrates this behavior.</p> + +<pre class="brush: js">var arr = Array(9.3); // RangeError: Invalid array length +</pre> + +<p>If your code needs to create arrays with single elements of an arbitrary data type, it is safer to use array literals. Or, create an empty array first before adding the single element to it.</p> + +<h3 id="Populating_an_array">Populating an array</h3> + +<p>You can populate an array by assigning values to its elements. For example,</p> + +<pre class="brush: js">var emp = []; +emp[0] = 'Casey Jones'; +emp[1] = 'Phil Lesh'; +emp[2] = 'August West'; +</pre> + +<div class="note"> +<p><strong>Note :</strong> if you supply a non-integer value to the array operator in the code above, a property will be created in the object representing the array, instead of an array element.</p> +</div> + +<pre class="brush: js">var arr = []; +arr[3.4] = 'Oranges'; +console.log(arr.length); // 0 +console.log(arr.hasOwnProperty(3.4)); // true +</pre> + +<p>You can also populate an array when you create it:</p> + +<pre class="brush: js">var myArray = new Array('Hello', myVar, 3.14159); +var myArray = ['Mango', 'Apple', 'Orange']; +</pre> + +<h3 id="Referring_to_array_elements">Referring to array elements</h3> + +<p>You refer to an array's elements by using the element's ordinal number. For example, suppose you define the following array:</p> + +<pre class="brush: js">var myArray = ['Wind', 'Rain', 'Fire']; +</pre> + +<p>You then refer to the first element of the array as <code>myArray[0]</code> and the second element of the array as <code>myArray[1]</code>. The index of the elements begins with zero.</p> + +<div class="note"> +<p><strong>Note :</strong> the array operator (square brackets) is also used for accessing the array's properties (arrays are also objects in JavaScript). For example,</p> +</div> + +<pre class="brush: js">var arr = ['one', 'two', 'three']; +arr[2]; // three +arr['length']; // 3 +</pre> + +<h3 id="Understanding_length">Understanding length</h3> + +<p>At the implementation level, JavaScript's arrays actually store their elements as standard object properties, using the array index as the property name. The <code>length</code> property is special; it always returns the index of the last element plus one (in the following example, Dusty is indexed at 30, so cats.length returns 30 + 1). Remember, JavaScript Array indexes are 0-based: they start at 0, not 1. This means that the <code>length</code> property will be one more than the highest index stored in the array:</p> + +<pre class="brush: js">var cats = []; +cats[30] = ['Dusty']; +console.log(cats.length); // 31 +</pre> + +<p>You can also assign to the <code>length</code> property. Writing a value that is shorter than the number of stored items truncates the array; writing 0 empties it entirely:</p> + +<pre class="brush: js">var cats = ['Dusty', 'Misty', 'Twiggy']; +console.log(cats.length); // 3 + +cats.length = 2; +console.log(cats); // logs "Dusty, Misty" - Twiggy has been removed + +cats.length = 0; +console.log(cats); // logs nothing; the cats array is empty + +cats.length = 3; +console.log(cats); // [undefined, undefined, undefined] +</pre> + +<h3 id="Iterating_over_arrays">Iterating over arrays</h3> + +<p>A common operation is to iterate over the values of an array, processing each one in some way. The simplest way to do this is as follows:</p> + +<pre class="brush: js">var colors = ['red', 'green', 'blue']; +for (var i = 0; i < colors.length; i++) { + console.log(colors[i]); +} +</pre> + +<p>If you know that none of the elements in your array evaluate to <code>false</code> in a boolean context — if your array consists only of <a href="/en-US/docs/DOM" title="en-US/docs/DOM">DOM</a> nodes, for example, you can use a more efficient idiom:</p> + +<pre class="brush: js">var divs = document.getElementsByTagName('div'); +for (var i = 0, div; div = divs[i]; i++) { + /* Process div in some way */ +} +</pre> + +<p>This avoids the overhead of checking the length of the array, and ensures that the <code>div</code> variable is reassigned to the current item each time around the loop for added convenience.</p> + +<p>The {{jsxref("Array.forEach", "forEach()")}} method provides another way of iterating over an array:</p> + +<pre class="brush: js">var colors = ['red', 'green', 'blue']; +colors.forEach(function(color) { + console.log(color); +}); +// red +// green +// blue +</pre> + +<p>Alternatively, You can shorten the code for the forEach parameter with ES6 Arrow Functions:</p> + +<pre class="brush: js">var colors = ['red', 'green', 'blue']; +colors.forEach(color => console.log(color)); +// red +// green +// blue +</pre> + +<p>The function passed to <code>forEach</code> is executed once for every item in the array, with the array item passed as the argument to the function. Unassigned values are not iterated in a <code>forEach</code> loop.</p> + +<p>Note that the elements of array that are omitted when the array is defined are not listed when iterating by <code>forEach</code>, but are listed when <code>undefined</code> has been manually assigned to the element:</p> + +<pre class="brush: js">var array = ['first', 'second', , 'fourth']; + +array.forEach(function(element) { + console.log(element); +}); +// first +// second +// fourth + +if (array[2] === undefined) { + console.log('array[2] is undefined'); // true +} + +array = ['first', 'second', undefined, 'fourth']; + +array.forEach(function(element) { + console.log(element); +}); +// first +// second +// undefined +// fourth +</pre> + +<p>Since JavaScript elements are saved as standard object properties, it is not advisable to iterate through JavaScript arrays using {{jsxref("Statements/for...in","for...in")}} loops because normal elements and all enumerable properties will be listed.</p> + +<h3 id="Array_methods">Array methods</h3> + +<p>The {{jsxref("Array")}} object has the following methods:</p> + +<p>{{jsxref("Array.concat", "concat()")}} joins two arrays and returns a new array.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3'); +myArray = myArray.concat('a', 'b', 'c'); +// myArray is now ["1", "2", "3", "a", "b", "c"] +</pre> + +<p>{{jsxref("Array.join", "join(deliminator = ',')")}} joins all elements of an array into a string.</p> + +<pre class="brush: js">var myArray = new Array('Wind', 'Rain', 'Fire'); +var list = myArray.join(' - '); // list is "Wind - Rain - Fire" +</pre> + +<p>{{jsxref("Array.push", "push()")}} adds one or more elements to the end of an array and returns the resulting length of the array.</p> + +<pre class="brush: js">var myArray = new Array('1', '2'); +myArray.push('3'); // myArray is now ["1", "2", "3"] +</pre> + +<p>{{jsxref("Array.pop", "pop()")}} removes the last element from an array and returns that element.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3'); +var last = myArray.pop(); +// myArray is now ["1", "2"], last = "3" +</pre> + +<p>{{jsxref("Array.shift", "shift()")}} removes the first element from an array and returns that element.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3'); +var first = myArray.shift(); +// myArray is now ["2", "3"], first is "1" +</pre> + +<p>{{jsxref("Array.unshift", "unshift()")}} adds one or more elements to the front of an array and returns the new length of the array.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3'); +myArray.unshift('4', '5'); +// myArray becomes ["4", "5", "1", "2", "3"]</pre> + +<p>{{jsxref("Array.slice", "slice(start_index, upto_index)")}} extracts a section of an array and returns a new array.</p> + +<pre class="brush: js">var myArray = new Array('a', 'b', 'c', 'd', 'e'); +myArray = myArray.slice(1, 4); // starts at index 1 and extracts all elements + // until index 3, returning [ "b", "c", "d"] +</pre> + +<p>{{jsxref("Array.splice", "splice(index, count_to_remove, addElement1, addElement2, ...)")}} removes elements from an array and (optionally) replaces them. It returns the items which were removed from the array.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3', '4', '5'); +myArray.splice(1, 3, 'a', 'b', 'c', 'd'); +// myArray is now ["1", "a", "b", "c", "d", "5"] +// This code started at index one (or where the "2" was), +// removed 3 elements there, and then inserted all consecutive +// elements in its place. +</pre> + +<p>{{jsxref("Array.reverse", "reverse()")}} transposes the elements of an array, in place: the first array element becomes the last and the last becomes the first. It returns a reference to the array.</p> + +<pre class="brush: js">var myArray = new Array('1', '2', '3'); +myArray.reverse(); +// transposes the array so that myArray = ["3", "2", "1"] +</pre> + +<p>{{jsxref("Array.sort", "sort()")}} sorts the elements of an array in place, and returns a reference to the array.</p> + +<pre class="brush: js">var myArray = new Array('Wind', 'Rain', 'Fire'); +myArray.sort(); +// sorts the array so that myArray = ["Fire", "Rain", "Wind"] +</pre> + +<p><code>sort()</code> can also take a callback function to determine how array elements are compared.</p> + +<p>The sort method and other methods below that take a callback are known as <em>iterative methods</em>, because they iterate over the entire array in some fashion. Each one takes an optional second argument called <code>thisObject</code>. If provided, <code>thisObject</code> becomes the value of the <code>this</code> keyword inside the body of the callback function. If not provided, as with other cases where a function is invoked outside of an explicit object context, <code>this</code> will refer to the global object ({{domxref("window")}}).</p> + +<p>The callback function is called with two arguments, that are array's elements.</p> + +<p>The function below compares two values and returns one of three values:</p> + +<p>For instance, the following will sort by the last letter of a string:</p> + +<pre class="brush: js">var sortFn = function(a, b) { + if (a[a.length - 1] < b[b.length - 1]) return -1; + if (a[a.length - 1] > b[b.length - 1]) return 1; + if (a[a.length - 1] == b[b.length - 1]) return 0; +} +myArray.sort(sortFn); +// sorts the array so that myArray = ["Wind","Fire","Rain"]</pre> + +<ul> + <li>if <code>a</code> is less than <code>b</code> by the sorting system, return -1 (or any negative number)</li> + <li>if <code>a</code> is greater than <code>b</code> by the sorting system, return 1 (or any positive number)</li> + <li>if <code>a</code> and <code>b</code> are considered equivalent, return 0.</li> +</ul> + +<p>{{jsxref("Array.indexOf", "indexOf(searchElement[, fromIndex])")}} searches the array for <code>searchElement</code> and returns the index of the first match.</p> + +<pre class="brush: js">var a = ['a', 'b', 'a', 'b', 'a']; +console.log(a.indexOf('b')); // logs 1 +// Now try again, starting from after the last match +console.log(a.indexOf('b', 2)); // logs 3 +console.log(a.indexOf('z')); // logs -1, because 'z' was not found +</pre> + +<p>{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement[, fromIndex])")}} works like <code>indexOf</code>, but starts at the end and searches backwards.</p> + +<pre class="brush: js">var a = ['a', 'b', 'c', 'd', 'a', 'b']; +console.log(a.lastIndexOf('b')); // logs 5 +// Now try again, starting from before the last match +console.log(a.lastIndexOf('b', 4)); // logs 1 +console.log(a.lastIndexOf('z')); // logs -1 +</pre> + +<p>{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} executes <code>callback</code> on every array item and returns undefined.</p> + +<pre class="brush: js">var a = ['a', 'b', 'c']; +a.forEach(function(element) { console.log(element); }); +// logs each item in turn +</pre> + +<p>{{jsxref("Array.map", "map(callback[, thisObject])")}} returns a new array of the return value from executing <code>callback</code> on every array item.</p> + +<pre class="brush: js">var a1 = ['a', 'b', 'c']; +var a2 = a1.map(function(item) { return item.toUpperCase(); }); +console.log(a2); // logs ['A', 'B', 'C'] +</pre> + +<p>{{jsxref("Array.filter", "filter(callback[, thisObject])")}} returns a new array containing the items for which callback returned true.</p> + +<pre class="brush: js">var a1 = ['a', 10, 'b', 20, 'c', 30]; +var a2 = a1.filter(function(item) { return typeof item === 'number'; }); +console.log(a2); // logs [10, 20, 30] +</pre> + +<p>{{jsxref("Array.every", "every(callback[, thisObject])")}} returns true if <code>callback</code> returns true for every item in the array.</p> + +<pre class="brush: js">function isNumber(value) { + return typeof value === 'number'; +} +var a1 = [1, 2, 3]; +console.log(a1.every(isNumber)); // logs true +var a2 = [1, '2', 3]; +console.log(a2.every(isNumber)); // logs false +</pre> + +<p>{{jsxref("Array.some", "some(callback[, thisObject])")}} returns true if <code>callback</code> returns true for at least one item in the array.</p> + +<pre class="brush: js">function isNumber(value) { + return typeof value === 'number'; +} +var a1 = [1, 2, 3]; +console.log(a1.some(isNumber)); // logs true +var a2 = [1, '2', 3]; +console.log(a2.some(isNumber)); // logs true +var a3 = ['1', '2', '3']; +console.log(a3.some(isNumber)); // logs false +</pre> + +<p>{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}} applies <code>callback(firstValue, secondValue)</code> to reduce the list of items down to a single value and returns that value.</p> + +<pre class="brush: js">var a = [10, 20, 30]; +var total = a.reduce(function(first, second) { return first + second; }, 0); +console.log(total) // Prints 60 +</pre> + +<p>{{jsxref("Array.reduceRight", "reduceRight(callback[, initialValue])")}} works like <code>reduce()</code>, but starts with the last element.</p> + +<p><code>reduce</code> and <code>reduceRight</code> are the least obvious of the iterative array methods. They should be used for algorithms that combine two values recursively in order to reduce a sequence down to a single value.</p> + +<h3 id="Multi-dimensional_arrays">Multi-dimensional arrays</h3> + +<p>Arrays can be nested, meaning that an array can contain another array as an element. Using this characteristic of JavaScript arrays, multi-dimensional arrays can be created.</p> + +<p>The following code creates a two-dimensional array.</p> + +<pre class="brush: js">var a = new Array(4); +for (i = 0; i < 4; i++) { + a[i] = new Array(4); + for (j = 0; j < 4; j++) { + a[i][j] = '[' + i + ', ' + j + ']'; + } +} +</pre> + +<p>This example creates an array with the following rows:</p> + +<pre>Row 0: [0, 0] [0, 1] [0, 2] [0, 3] +Row 1: [1, 0] [1, 1] [1, 2] [1, 3] +Row 2: [2, 0] [2, 1] [2, 2] [2, 3] +Row 3: [3, 0] [3, 1] [3, 2] [3, 3] +</pre> + +<h3 id="Arrays_and_regular_expressions">Arrays and regular expressions</h3> + +<p>When an array is the result of a match between a regular expression and a string, the array returns properties and elements that provide information about the match. An array is the return value of {{jsxref("Global_Objects/RegExp/exec","RegExp.exec()")}}, {{jsxref("Global_Objects/String/match","String.match()")}}, and {{jsxref("Global_Objects/String/split","String.split()")}}. For information on using arrays with regular expressions, see <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Regular Expressions</a>.</p> + +<h3 id="Working_with_array-like_objects">Working with array-like objects</h3> + +<p>Some JavaScript objects, such as the {{domxref("NodeList")}} returned by {{domxref("document.getElementsByTagName()")}} or the {{jsxref("Functions/arguments","arguments")}} object made available within the body of a function, look and behave like arrays on the surface but do not share all of their methods. The <code>arguments</code> object provides a {{jsxref("Global_Objects/Function/length","length")}} attribute but does not implement the {{jsxref("Array.forEach", "forEach()")}} method, for example.</p> + +<p>Array prototype methods can be called against other array-like objects. for example:</p> + +<pre class="brush: js">function printArguments() { + Array.prototype.forEach.call(arguments, function(item) { + console.log(item); + }); +} +</pre> + +<p>Array prototype methods can be used on strings as well, since they provide sequential access to their characters in a similar way to arrays:</p> + +<pre class="brush: js">Array.prototype.forEach.call('a string', function(chr) { + console.log(chr); +});</pre> + +<h2 id="Typed_Arrays">Typed Arrays</h2> + +<p><a href="/en-US/docs/Web/JavaScript/Typed_arrays">JavaScript typed arrays</a> are array-like objects and provide a mechanism for accessing raw binary data. As you already know, {{jsxref("Array")}} objects grow and shrink dynamically and can have any JavaScript value. JavaScript engines perform optimizations so that these arrays are fast. However, as web applications become more and more powerful, adding features such as audio and video manipulation, access to raw data using <a href="/en-US/docs/WebSockets">WebSockets</a>, and so forth, it has become clear that there are times when it would be helpful for JavaScript code to be able to quickly and easily manipulate raw binary data in typed arrays.</p> + +<h3 id="Buffers_and_views_typed_array_architecture">Buffers and views: typed array architecture</h3> + +<p>To achieve maximum flexibility and efficiency, JavaScript typed arrays split the implementation into <strong>buffers</strong> and <strong>views</strong>. A buffer (implemented by the {{jsxref("ArrayBuffer")}} object) is an object representing a chunk of data; it has no format to speak of, and offers no mechanism for accessing its contents. In order to access the memory contained in a buffer, you need to use a view. A view provides a context — that is, a data type, starting offset, and number of elements — that turns the data into an actual typed array.</p> + +<p><img alt="Typed arrays in an ArrayBuffer" src="https://mdn.mozillademos.org/files/8629/typed_arrays.png" style="height: 278px; width: 666px;"></p> + +<h3 id="ArrayBuffer">ArrayBuffer</h3> + +<p>The {{jsxref("ArrayBuffer")}} is a data type that is used to represent a generic, fixed-length binary data buffer. You can't directly manipulate the contents of an <code>ArrayBuffer</code>; instead, you create a typed array view or a {{jsxref("DataView")}} which represents the buffer in a specific format, and use that to read and write the contents of the buffer.</p> + +<h3 id="Typed_array_views">Typed array views</h3> + +<p>Typed array views have self descriptive names and provide views for all the usual numeric types like <code>Int8</code>, <code>Uint32</code>, <code>Float64</code> and so forth. There is one special typed array view, the <code>Uint8ClampedArray</code>. It clamps the values between 0 and 255. This is useful for <a href="/en-US/docs/Web/API/ImageData">Canvas data processing</a>, for example.</p> + +<p>{{page("/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", "TypedArray_objects")}}</p> + +<p>For more information, see <a href="/en-US/docs/Web/JavaScript/Typed_arrays">JavaScript typed arrays</a> and the reference documentation for the different {{jsxref("TypedArray")}} objects.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</p> diff --git a/files/zh-tw/web/javascript/guide/introduction/index.html b/files/zh-tw/web/javascript/guide/introduction/index.html new file mode 100644 index 0000000000..ab855f45fc --- /dev/null +++ b/files/zh-tw/web/javascript/guide/introduction/index.html @@ -0,0 +1,180 @@ +--- +title: JavaScript 概觀 +slug: Web/JavaScript/Guide/Introduction +translation_of: Web/JavaScript/Guide/Introduction +--- +<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</p> + +<p>這個章節的內容主要是介紹 JavaScript 和討論一些 JavaScript 的基本概念。</p> + +<h2 id="在開始前需具備之能力">在開始前需具備之能力</h2> + +<p>本手冊假設您具有以下基本背景:</p> + +<ul> + <li>對網際網路及全球資訊網有大致上的了解</li> + <li>對HTML(HyperText Markup Language )語法理解至一定程度</li> + <li>有寫過程式的經驗,若您是完全的新手,可嘗試在主頁上有關<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a>的教程。</li> +</ul> + +<p> </p> + +<h2 id="What_is_JavaScript.3F" name="What_is_JavaScript.3F">什麼是 JavaScript?</h2> + +<p>JavaScript 是個跨平台、物件導向、輕小型的腳本語言。作為獨立語言並不實用,而是為了能簡單嵌入其他產品和應用程式(例如:網頁瀏覽器)而設計。JavaScript 若寄宿在主體環境(Host environment)時,可以與環境中的物件 (Object)相連,並以程式控制這些物件。</p> + +<p>Core JavaScript 包含了物件的核心集合(例如: <code>Array、</code> <code>Date、</code> <code>Math</code>)及語言成份的核心集合(例如:運算子、控制結構、敘述)。在 Core JavaScript 增加額外的物件即可擴充各式各樣的功能,例如:</p> + +<ul> + <li>用戶端 - JavaScript 藉由提供物件來擴增核心語言達到控制網頁瀏覽器和其文件物件模型(DOM,Document Object Model)的目的。</li> +</ul> + +<p style="margin-left: 40px;">舉例來說:用戶端的擴充套件允許某個應用程式將元素放置在 HTML 的表單上及對使用者的操作(例如:滑鼠點選、表單輸入、頁面導覽等)做出回應。</p> + +<ul> + <li>伺服器端 - JavaScript 藉由提供和伺服器上執行 JavaScript 相關的物件來擴增核心語言。</li> +</ul> + +<p style="margin-left: 40px;">舉例來說:伺服器端的擴充套件允許某個應用程式和相關的資料庫交換訊息、對一個其他應用程式的呼叫提供連續性的資訊、在伺服器上執行檔案操作。</p> + +<p>透過 JavaScript 的 LiveConnect 功能,你可以使 Java 和 JavaScript 的程式碼彼此相連。在 JavaScript 的程式碼中,你可以實例化(instantiate)Java 的物件並存取那些物件的公有方法(public methods)及欄位(fields)。在 Java 的程式碼中,你可以存取 JavaScript 的物件、屬性(properties)及方法(methods)。</p> + +<p>Netscape 公司發明了 JavaScript ,而 JavaScript 的第一次使用正是在 Netscape 自家的瀏覽器上。</p> + +<h2 id="JavaScript_and_Java" name="JavaScript_and_Java">JavaScript 與 Java</h2> + +<p>JavaScript 與 Java 在某些方面非常相似但本質上卻是不同的。 JavaScript 雖然和 Java 類似,卻沒有 Java 的靜態定型(static typing)及強型態確認(strong type checking)特性。 JavaScript 遵從大部份的 Java 表達式語法、命名傳統和基本的流程控制概念,這特性同時也是為何要將 LiveScript 重新命名為 JavaScript 的原因。</p> + +<p>相較於 Java 由許多類別中的宣告建立的 compile-time 系統,JavaScript 支援一個由少數代表數值(numeric)、布林值(Boolean)、字串(string)的資料類型所構成的執行期函式庫(runtime system)。JavaScript 擁有一個基於原型的物件模型(prototype-based object model)而不是普遍使用的基於類別的物件模型(class-based object model)。基於原型的物件模型提供動態繼承(dynamic inheritance)的功能,意即被繼承的物件可以根據個別的物件而改變。JavaScript 也支援不需任何特殊宣告的函式,函式可以是物件的屬性,如同鬆散型態方法(loosely typed method)那樣執行。</p> + +<p>JavaScript 和 Java 相比起來,算是一個格式非常自由的語言。你不需要宣告所有的變數、類別(class)、方法,你不需要注意哪些方法是公有(public)或私有(private)或受保護的(protected),你不需要實作介面(interface)。變數、參數及函式回傳的型態並不是顯性型態。</p> + +<p>Java 是一個為了快速執行與安全型態而設計的基於類別的程式語言(class-based programming language)。安全型態意即你在 Java 中無法將整數丟給一個物件參考,也無法藉由中斷 Java bytecodes 來存取私有的記憶體。 Java 的基於類別模型(class-based model)意思是程式由專門的類別及其方法所組成。Java 的類別繼承(class inheritance)和強型別(strong typing)通常需要嚴謹的耦合對象階級(coupled object hierarchies)。這些需求使得 Java 在程式的撰寫上比 JavaScript 來的複雜。</p> + +<p>相反的,JavaScript 承襲了如同 HyperTalk 和 dBASE 相同的精神:較小、動態類型。 這些腳本語言因為較簡單的語法、特殊化的功能、較寬鬆的要求等特性,進而提供了許多軟體開發工具(programming tool)給更多更廣大的愛好者。</p> + +<p>表1.1 - JavaScript 和 Java 比較</p> + +<table class="standard-table"> + <caption> </caption> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td> + <p>物件導向。</p> + + <p>物件的型態之間無區別。</p> + + <p>藉由原型機制(prototype mechanism)和屬性(properties)實行繼承。</p> + + <p>屬性和方法可被動態新增至任何物件。</p> + </td> + <td> + <p>類別導向。</p> + + <p>物件藉由類別階級(class hierarchy)而被分離至類別和所有繼承的實體(instance)中。</p> + + <p>類別和實體無法動態新增屬性和方法。</p> + </td> + </tr> + <tr> + <td> + <p>變數資料型態沒有宣告就可使用(動態定型,dynamic typing)。</p> + </td> + <td> + <p>變數資料型態必須宣告才可使用(靜態定型,static typing)。</p> + </td> + </tr> + <tr> + <td>無法自動覆寫到硬碟。</td> + <td>無法自動覆寫到硬碟。</td> + </tr> + </tbody> +</table> + +<p>更多關於 JavaScript 和 Java 的差異比較,請參見 <a href="/zh-TW/docs/JavaScript/Guide/Details_of_the_Object_Model" title="JavaScript/Guide/Details of the Object Model">Details of the Object Model</a> 。</p> + +<h2 id="JavaScript_and_the_ECMAScript_Specification" name="JavaScript_and_the_ECMAScript_Specification">JavaScript 與 ECMAScript 規格</h2> + +<p>Netscape 公司發明了 JavaScript ,而 JavaScript 的第一次應用正是在 Netscape 瀏覽器。然而,Netscape 後來和 <a class="external" href="http://www.ecma-international.org/">Ecma International</a>(一個致力於將資訊及通訊系統標準化的歐洲組織,前身為 ECMA - 歐洲計算機製造商協會)合作,開發一個基於 JavaScript 核心並同時兼具標準化與國際化的程式語言,這個經過標準化的 JavaScript 便稱作 ECMAScript ,和 JavaScript 有著相同的應用方式並支援相關標準。各個公司都可以使用這個開放的標準語言去開發 JavaScript 的專案。ECMAScript 標準記載於 ECMA-262 這個規格中。</p> + +<p>ECMA-262 標準同時也經過 <a class="external" href="http://www.iso.ch/">ISO</a>(國際標準化組織)認証,成為 ISO-16262 標準。你可以在 Mozilla 的網站上找到 <a class="external" href="http://www-archive.mozilla.org/js/language/E262-3.pdf" title="http://www-archive.mozilla.org/js/language/E262-3.pdf">PDF版本的ECMA-262</a>,但這板本已過期;你也可以在<a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"> Ecma International 的網站</a> 找到這個規格。 ECMAScript 規格中並沒有描述已經被 W3C(全球資訊網協會)標準化的文件物件模型(DOM)。文件物件模型定義了 HTML 文件物件(document objects)和腳本之間運作的方式。</p> + +<h3 id="Relationship_between_JavaScript_Versions_and_ECMAScript_Editions" name="Relationship_between_JavaScript_Versions_and_ECMAScript_Editions">JavaScript 版本與 ECMAScript 版本之間的關係</h3> + +<p>ECMAScript 規格(ECMA-262)在 Netscape 和 Ecma International 的密切合作下產生。下表描述了 JavaScript 的版本和 ECMAScript 的版本之間的關係。</p> + +<p>表1.2 - JavaScript 版本及 ECMAScript 版本</p> + +<table class="standard-table"> + <caption> </caption> + <thead> + <tr> + <th scope="row" style="width: 9em;">JavaScript 的版本</th> + <th scope="col">和 ECMAScript 版本的關係</th> + </tr> + </thead> + <tbody> + <tr> + <td>JavaScript 1.1</td> + <td>ECMA-262 第1版是基於 JavaScript 1.1 建立的。</td> + </tr> + <tr> + <td>JavaScript 1.2</td> + <td> + <p>ECMA-262 在 JavaScript 1.2 發行之際尚未完成。以下是 JavaScript 1.2 並未完全相容於 ECMA-262 第1版的原因:</p> + + <ul> + <li>Netscape 在 JavaScript 1.2 中新增了一些特性,而這些特性在 ECMA-262 並未被考慮到。</li> + <li>ECMA-262 新增了兩個新的特性:使用國際化的 Unicode 編碼及統一了不同平台之間的行為。JavaScript 1.2 中的一些特性,例如:日期物件(Date object)是具有平台依賴性(platform-dependent)並且使用平台特製化行為(platform-specific behavior)的。</li> + </ul> + </td> + </tr> + <tr> + <td>JavaScript 1.3</td> + <td> + <p>JavaScript 1.3 完全相容於 ECMA-262 第1版。</p> + JavaScript 1.3 藉由保留所有在 JavaScript 1.2 新增的特性(除了 == 和 != 以外,因為要和 ECMA-262 一致),解決了 JavaScript 1.2 和 ECMA-262 之間的衝突。</td> + </tr> + <tr> + <td>JavaScript 1.4</td> + <td> + <p>JavaScript 1.4 完全相容於 ECMA-262 第1版。</p> + ECMAScript 第3版規格在 JavaScript 1.4 發行之際尚未完成。</td> + </tr> + <tr> + <td>JavaScript 1.5</td> + <td>JavaScript 1.5 完全相容於 ECMA-262 第3版。</td> + </tr> + </tbody> +</table> + +<div class="note">注意:ECMA-262 第2版是由已修正錯誤的第1版並加上些微的更動構成。現今由 Ecma International 的 TC39 工作組(TC39 Working Group)所發行的版本是 ECMAScript 5.1版</div> + +<p><a href="/zh-TW/docs/JavaScript/Reference" title="JavaScript/Reference">JavaScript Reference</a> 指出了哪些 JavaScript 的特性是相容於 ECMAScript 的。</p> + +<p>JavaScript 永遠包含許多非 ECMAScript 規格中的特性;</p> + +<p>JavaScript 不僅相容於 ECMAScript 更提供了額外的特性。</p> + +<h3 id="JavaScript_Documentation_versus_the_ECMAScript_Specification" name="JavaScript_Documentation_versus_the_ECMAScript_Specification">JavaScript 使用說明 v.s ECMAScript 規格</h3> + +<p>ECMAScript 規格是執行 ECMAScript 所必須的條件,當你想判斷某個 JavaScript 的特性是否在其他 ECMAScript 實作中有被支援時,ECMAScript 規格是非常有用的。如果你打算撰寫 JavaScript 程式碼並在程式碼中使用僅有 ECMAScript 所支援的特性,那你可能需要查閱一下 ECMAScript 規格。</p> + +<p>ECMAScript 文件並不是為了幫助腳本程式設計師而撰寫,如果想知道撰寫腳本的相關資訊,請參考 JavaScript 使用說明。</p> + +<h3 id="JavaScript_and_ECMAScript_Terminology" name="JavaScript_and_ECMAScript_Terminology">JavaScript 和 ECMAScript 的專門術語</h3> + +<p>ECMAScript 規格使用的術語和語法對於 JavaScript 的程式設計師來說可能不是那麼的親切。雖然語言的描述在 ECMAScript 中可能會有所不同,但語言本身的性質仍然是不變的。JavaScript 支援所有在 ECMAScript 規格中被描述到的功能。</p> + +<p>JavaScript 使用說明對於語言的觀點的描述較適合 JavaScript 的程式設計師。例如:</p> + +<ul> + <li>因為全域物件(Global Object)並不會被直接使用,所以並沒有在 JavaScript 文件說明中被論及。而像是全域物件的方法和屬性這些有被使用到的,就有在 JavaScript 使用說明中被論及,但被稱作頂層(top-level)函式和頂層屬性。</li> + <li>無參數建構函式(no parameter constructor,也稱作零參數建構函式,zero-argument constructor)。帶有 Number 物件及 String 物件的無參數建構函式並沒有在 JavaScript 使用說明中被論及,因為其產生出來的東西用途有限:一個沒有參數的 Number 建構函式回傳 +0 、一個沒有參數的 String 建構函式回傳 "" (一個空字串)</li> +</ul> diff --git a/files/zh-tw/web/javascript/guide/iterators_and_generators/index.html b/files/zh-tw/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..6ad6128a6f --- /dev/null +++ b/files/zh-tw/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,193 @@ +--- +title: Iterators and generators +slug: Web/JavaScript/Guide/Iterators_and_Generators +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</div> + +<p class="summary">處理集合中的每個項目是很常見的操作,JavaScript提供了許多迭代集合的方法,從簡單的 {{jsxref("Statements/for","for")}} 循環到 {{jsxref("Global_Objects/Array/map","map()")}} 和 {{jsxref("Global_Objects/Array/filter","filter()")}}。</p> + +<p class="summary">Iterators 和 Generators 將迭代的概念直接帶進核心語言,並提供一個機制來客製化 {{jsxref("Statements/for...of","for...of")}} 的循環行為。</p> + +<p>更多詳情請參考:</p> + +<ul> + <li>{{jsxref("Iteration_protocols")}}</li> + <li>{{jsxref("Statements/for...of","for...of")}}</li> + <li>{{jsxref("Statements/function*","function*")}} 和 {{jsxref("Generator")}}</li> + <li>{{jsxref("Operators/yield","yield")}} 和 {{jsxref("Operators/yield*","yield*")}}</li> +</ul> + +<h2 id="Iterators_疊代器">Iterators (疊代器)</h2> + +<p>在 JavaScript 中,<strong>iterator</strong> 是一個物件(object),他定義一個序列,並在終止時回傳一個值。</p> + +<p>更精確地說,iterator 是任何一個透過 <code>next()</code> 方法實現 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">Iterator protocol</a> 的物件,該方法回傳具有以下兩個屬性 (property) 的物件:</p> + +<dl> + <dt><code><var>value</var></code></dt> + <dd>在 iteration 序列中的下一個值。</dd> + <dt><code><var>done</var></code></dt> + <dd>如果序列中的最後一個值已經被消耗(使用)了,則此值為 <code>true</code> 。如果 <code><var>value</var></code> 和 <code><var>done</var></code> 一起存在, 則他是這個 iterator 的回傳值。</dd> +</dl> + +<p>一旦建立 iterator 物件後,可以透過反覆呼叫 <code>next()</code> 來進行迭代。 iterator 經過迭代後,即被認為已經消耗iterator ,因為通常只可能執行一次。在產生終止值之後,對 <code>next()</code> 的其他調用應僅繼續返回{done:true}。<br> + <br> + The most common iterator in Javascript is the Array iterator, which simply returns each value in the associated array in sequence. While it is easy to imagine that all iterators could be expressed as arrays, this is not true. Arrays must be allocated in their entirety, but iterators are consumed only as necessary and thus can express sequences of unlimited size, such as the range of integers between 0 and Infinity.<br> + <br> + Here is an example which can do just that. It allows creation of a simple range iterator which defines a sequence of integers from <code>start</code> (inclusive) to <code>end</code> (exclusive) spaced <code>step</code> apart. Its final return value is the size of the sequence it created, tracked by the variable iterationCount.</p> + +<pre class="brush: js">function makeRangeIterator(start = 0, end = Infinity, step = 1) { + let nextIndex = start; + let iterationCount = 0; + + const rangeIterator = { + next: function() { + let result; + if (nextIndex <= end) { + result = { value: nextIndex, done: false } + nextIndex += step; + iterationCount++; + return result; + } + return { value: iterationCount, done: true } + } + }; + return rangeIterator; +}</pre> + +<p>Using the iterator then looks like this:</p> + +<pre class="brush: js">let it = makeRangeIterator(1, 10, 2); + +let result = it.next(); +while (!result.done) { + console.log(result.value); // 1 3 5 7 9 + result = it.next(); +} + +console.log("Iterated over sequence of size: ", result.value); // 5 + +</pre> + +<div class="note"> +<p>It is not possible to know reflectively whether a particular object is an iterator. If you need to do this, use <a href="#Iterables">Iterables</a>.</p> +</div> + +<h2 id="Generator_functions">Generator functions</h2> + +<p>While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generator functions provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function whose execution is not continuous. Generator functions are written using the {{jsxref("Statements/function*","function*")}} syntax. When called initially, generator functions do not execute any of their code, instead returning a type of iterator called a Generator. When a value is consumed by calling the generator's <strong>next</strong> method, the Generator function executes until it encounters the <strong>yield</strong> keyword.</p> + +<p>The function can be called as many times as desired and returns a new Generator each time, however each Generator may only be iterated once.<br> + <br> + We can now adapt the example from above. The behavior of this code is identical, but the implementation is much easier to write and read.</p> + +<pre class="brush: js">function* makeRangeIterator(start = 0, end = 100, step = 1) { + for (let i = start; i < end; i += step) { + yield i; + } +}</pre> + +<h2 id="Iterables">Iterables</h2> + +<p>An object is <strong>iterable</strong> if it defines its iteration behavior, such as what values are looped over in a {{jsxref("Statements/for...of", "for...of")}} construct. Some built-in types, such as {{jsxref("Array")}} or {{jsxref("Map")}}, have a default iteration behavior, while other types (such as {{jsxref("Object")}}) do not.</p> + +<p>In order to be <strong>iterable</strong>, an object must implement the <strong>@@iterator</strong> method, meaning that the object (or one of the objects up its <a href="/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">prototype chain</a>) must have a property with a {{jsxref("Symbol.iterator")}} key.<br> + <br> + It may be possible to iterate over an iterable more than once, or only once. It is up to the programmer to know which is the case. Iterables which can iterate only once (e.g. Generators) customarily return <strong>this</strong> from their <strong>@@iterator</strong> method, where those which can be iterated many times must return a new iterator on each invocation of <strong>@@iterator</strong>.</p> + +<h3 id="User-defined_iterables">User-defined iterables</h3> + +<p>We can make our own iterables like this:</p> + +<pre class="brush: js">var myIterable = { + *[Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + } +} + +for (let value of myIterable) { + console.log(value); +} +// 1 +// 2 +// 3 + +or + +[...myIterable]; // [1, 2, 3] +</pre> + +<h3 id="Built-in_iterables">Built-in iterables</h3> + +<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} and {{jsxref("Set")}} are all built-in iterables, because their prototype objects all have a {{jsxref("Symbol.iterator")}} method.</p> + +<h3 id="Syntaxes_expecting_iterables">Syntaxes expecting iterables</h3> + +<p>Some statements and expressions are expecting iterables, for example the {{jsxref("Statements/for...of","for-of")}} loops, {{jsxref("Operators/yield*","yield*")}}.</p> + +<pre class="brush: js">for (let value of ['a', 'b', 'c']) { + console.log(value); +} +// "a" +// "b" +// "c" + +[...'abc']; // ["a", "b", "c"] + +function* gen() { + yield* ['a', 'b', 'c']; +} + +gen().next(); // { value: "a", done: false } + +[a, b, c] = new Set(['a', 'b', 'c']); +a; // "a" + +</pre> + +<h2 id="Advanced_generators">Advanced generators</h2> + +<p>Generators compute their yielded values on demand, which allows them to efficiently represent sequences that are expensive to compute, or even infinite sequences as demonstrated above.</p> + +<p>The {{jsxref("Global_Objects/Generator/next","next()")}} method also accepts a value which can be used to modify the internal state of the generator. A value passed to <code>next()</code> will be treated as the result of the last <code>yield</code> expression that paused the generator.</p> + +<p>Here is the fibonacci generator using <code>next(x)</code> to restart the sequence:</p> + +<pre class="brush: js">function* fibonacci() { + var fn1 = 0; + var fn2 = 1; + while (true) { + var current = fn1; + fn1 = fn2; + fn2 = current + fn1; + var reset = yield current; + if (reset) { + fn1 = 0; + fn2 = 1; + } + } +} + +var sequence = fibonacci(); +console.log(sequence.next().value); // 0 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 2 +console.log(sequence.next().value); // 3 +console.log(sequence.next().value); // 5 +console.log(sequence.next().value); // 8 +console.log(sequence.next(true).value); // 0 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 2</pre> + +<p>You can force a generator to throw an exception by calling its {{jsxref("Global_Objects/Generator/throw","throw()")}} method and passing the exception value it should throw. This exception will be thrown from the current suspended context of the generator, as if the <code>yield</code> that is currently suspended were instead a <code>throw <em>value</em></code> statement.</p> + +<p>If the exception is not caught from within the generator, it will propagate up through the call to <code>throw()</code>, and subsequent calls to <code>next()</code> will result in the <code>done</code> property being <code>true</code>.</p> + +<p>Generators have a {{jsxref("Global_Objects/Generator/return","return(value)")}} method that returns the given value and finishes the generator itself.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</p> diff --git a/files/zh-tw/web/javascript/guide/keyed_collections/index.html b/files/zh-tw/web/javascript/guide/keyed_collections/index.html new file mode 100644 index 0000000000..ef0fa369dc --- /dev/null +++ b/files/zh-tw/web/javascript/guide/keyed_collections/index.html @@ -0,0 +1,156 @@ +--- +title: 鍵值集合 +slug: Web/JavaScript/Guide/Keyed_collections +tags: + - Collections + - Guide + - JavaScript + - Map + - set +translation_of: Web/JavaScript/Guide/Keyed_collections +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</div> + +<p class="summary">本章介紹用 “key” 來整理的資料集合 ; Map 和 Set objects 相當於多個可重複的元素依照插入順序進行排序。</p> + +<h2 id="Maps">Maps</h2> + +<h3 id="Map_object"><code>Map</code> object</h3> + +<p>ECMAScript 2015 引進了新的資料結構用以映射變量至變量。A {{jsxref("Map")}} object is a simple key/value map and can iterate its elements in insertion order</p> + +<p>The following code shows some basic operations with a <code>Map</code>. See also the {{jsxref("Map")}} reference page for more examples and the complete API. You can use a {{jsxref("Statements/for...of","for...of")}} loop to return an array of <code>[key, value]</code> for each iteration.</p> + +<pre class="brush: js">var sayings = new Map(); +sayings.set('dog', 'woof'); +sayings.set('cat', 'meow'); +sayings.set('elephant', 'toot'); +sayings.size; // 3 +sayings.get('fox'); // undefined +sayings.has('bird'); // false +sayings.delete('dog'); +sayings.has('dog'); // false + +for (var [key, value] of sayings) { + console.log(key + ' goes ' + value); +} +// "cat goes meow" +// "elephant goes toot" + +sayings.clear(); +sayings.size; // 0 +</pre> + +<h3 id="Object_and_Map_compared"><code>Object</code> and <code>Map</code> compared</h3> + +<p>Traditionally, {{jsxref("Object", "objects", "", 1)}} have been used to map strings to values. Objects allow you to set keys to values, retrieve those values, delete keys, and detect whether something is stored at a key. <code>Map</code> objects, however, have a few more advantages that make them better maps.</p> + +<ul> + <li>The keys of an <code>Object</code> are {{jsxref("Global_Objects/String","Strings")}}, where they can be of any value for a <code>Map</code>.</li> + <li>You can get the size of a <code>Map</code> easily while you have to manually keep track of size for an <code>Object</code>.</li> + <li>The iteration of maps is in insertion order of the elements.</li> + <li>An <code>Object</code> has a prototype, so there are default keys in the map. (this can be bypassed using <code>map = Object.create(null)</code>).</li> +</ul> + +<p>These three tips can help you to decide whether to use a <code>Map</code> or an <code>Object</code>:</p> + +<ul> + <li>Use maps over objects when keys are unknown until run time, and when all keys are the same type and all values are the same type.</li> + <li>Use maps in case if there is a need to store primitive values as keys because object treats each key as a string whether it's a number value, boolean value or any other primitive value.</li> + <li>Use objects when there is logic that operates on individual elements.</li> +</ul> + +<h3 id="WeakMap_object"><code>WeakMap</code> object</h3> + +<p>The {{jsxref("WeakMap")}} object is a collection of key/value pairs in which the <strong>keys are objects only</strong> and the values can be arbitrary values. The object references in the keys are held <em>weakly</em>, meaning that they are a target of garbage collection (GC) if there is no other reference to the object anymore. The <code>WeakMap</code> API is the same as the <code>Map</code> API.</p> + +<p>One difference to <code>Map</code> objects is that <code>WeakMap</code> keys are not enumerable (i.e., there is no method giving you a list of the keys). If they were, the list would depend on the state of garbage collection, introducing non-determinism.</p> + +<p>For more information and example code, see also "Why <em>Weak</em>Map?" on the {{jsxref("WeakMap")}} reference page.</p> + +<p>One use case of <code>WeakMap</code> objects is to store private data for an object or to hide implementation details. The following example is from Nick Fitzgerald's blog post <a href="http://fitzgeraldnick.com/weblog/53/">"Hiding Implementation Details with ECMAScript 6 WeakMaps"</a>. The private data and methods belong inside the object and are stored in the <code>privates</code> WeakMap object. Everything exposed on the instance and prototype is public; everything else is inaccessible from the outside world because <code>privates</code> is not exported from the module</p> + +<pre class="brush: js">const privates = new WeakMap(); + +function Public() { + const me = { + // Private data goes here + }; + privates.set(this, me); +} + +Public.prototype.method = function() { + const me = privates.get(this); + // Do stuff with private data in `me`... +}; + +module.exports = Public; +</pre> + +<h2 id="Sets">Sets</h2> + +<h3 id="Set_object"><code>Set</code> object</h3> + +<p>{{jsxref("Set")}} objects 是變數的集合。 You can iterate its elements in insertion order. A value in a <code>Set</code> may only occur once; it is unique in the <code>Set</code>'s collection.</p> + +<p>The following code shows some basic operations with a <code>Set</code>. See also the {{jsxref("Set")}} reference page for more examples and the complete API.</p> + +<pre class="brush: js">var mySet = new Set(); +mySet.add(1); +mySet.add('some text'); +mySet.add('foo'); + +mySet.has(1); // true +mySet.delete('foo'); +mySet.size; // 2 + +for (let item of mySet) console.log(item); +// 1 +// "some text" +</pre> + +<h3 id="Array_和_Set_之間的相互轉換">Array 和 Set 之間的相互轉換</h3> + +<p>You can create an {{jsxref("Array")}} from a Set using {{jsxref("Array.from")}} or the <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">spread operator</a>. Also, the <code>Set</code> constructor accepts an <code>Array</code> to convert in the other direction. Note again that <code>Set</code> objects store unique values, so any duplicate elements from an Array are deleted when converting.</p> + +<pre class="brush: js">Array.from(mySet); +[...mySet2]; + +mySet2 = new Set([1, 2, 3, 4]); +</pre> + +<h3 id="比較_Array_和_Set"><code>比較 Array</code> 和 <code>Set</code> </h3> + +<p>Traditionally, a set of elements has been stored in arrays in JavaScript in a lot of situations. The new <code>Set</code> object, however, has some advantages:</p> + +<ul> + <li>Checking whether an element exists in a collection using {{jsxref("Array.indexOf", "indexOf")}} for arrays is slow.</li> + <li><code>Set</code> objects let you delete elements by their value. With an array you would have to splice based on an element's index.</li> + <li>The value {{jsxref("NaN")}} cannot be found with <code>indexOf</code> in an array.</li> + <li><code>Set</code> objects store unique values; you don't have to keep track of duplicates by yourself.</li> +</ul> + +<h3 id="WeakSet_object"><code>WeakSet</code> object</h3> + +<p>{{jsxref("WeakSet")}} objects are collections of objects. An object in the <code>WeakSet</code> may only occur once; it is unique in the <code>WeakSet</code>'s collection and objects are not enumerable.</p> + +<p>The main differences to the {{jsxref("Set")}} object are:</p> + +<ul> + <li>In contrast to <code>Sets</code>, <code>WeakSets</code> are <strong>collections of objects only</strong> and not of arbitrary values of any type.</li> + <li>The <code>WeakSet</code> is <em>weak</em>: References to objects in the collection are held weakly. If there is no other reference to an object stored in the <code>WeakSet</code>, they can be garbage collected. That also means that there is no list of current objects stored in the collection. <code>WeakSets</code> are not enumerable.</li> +</ul> + +<p>The use cases of <code>WeakSet</code> objects are limited. They will not leak memory so it can be safe to use DOM elements as a key and mark them for tracking purposes, for example.</p> + +<h2 id="Key_and_value_equality_of_Map_and_Set">Key and value equality of <code>Map</code> and <code>Set</code></h2> + +<p>Both the key equality of <code>Map</code> objects and the value equality of <code>Set</code> objects, are based on the "<a href="https://tc39.github.io/ecma262/#sec-samevaluezero">same-value-zero algorithm</a>":</p> + +<ul> + <li>Equality works like the identity comparison operator <code>===</code>.</li> + <li><code>-0</code> and <code>+0</code> are considered equal.</li> + <li>{{jsxref("NaN")}} is considered equal to itself (contrary to <code>===</code>).</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</p> diff --git a/files/zh-tw/web/javascript/guide/loops_and_iteration/index.html b/files/zh-tw/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..ca913c3d2e --- /dev/null +++ b/files/zh-tw/web/javascript/guide/loops_and_iteration/index.html @@ -0,0 +1,337 @@ +--- +title: Loops and iteration +slug: Web/JavaScript/Guide/Loops_and_iteration +tags: + - JavaScript + - Loop + - 教學 + - 迴圈 +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</div> + +<p class="summary">迴圈提供一個快速又簡潔的方法來重複地做某件事。這個章節的<a href="/zh-TW/docs/Web/JavaScript/Guide">JavaScript教學</a>會介紹在JavaScript可以使用的幾種不同的迭代陳述式。 </p> + +<p>你可以將迴圈想成一個電腦版本的"往一個方向走X步,然後往另一個方向走Y步"的遊戲;作為範例,"往東走五步"可以用這個方法用迴圈表示:</p> + +<pre class="brush: js">var step; +for (step = 0; step < 5; step++) { + // 執行五次:從step為0到4 + console.log('Walking east one step'); +} +</pre> + +<p>有很多種不同種類的迴圈, 不過他們本質上都是做一樣的事:把一件動作重複地做一定的次數(而且也有可能做0次)。 各式各樣的迴圈機制提供了不同的方法來定義該迴圈的起始與結束。有些不同的情況下使用其中一種迴圈會比使用別種容易許多。</p> + +<p>在javaScript中提供的迴圈陳述式分別為:</p> + +<ul> + <li>{{anch("for 陳述式")}}</li> + <li>{{anch("do...while 陳述式")}}</li> + <li>{{anch("while 陳述式")}}</li> + <li>{{anch("label 陳述式")}}</li> + <li>{{anch("break 陳述式")}}</li> + <li>{{anch("continue 陳述式")}}</li> + <li>{{anch("for...in 陳述式")}}</li> + <li>{{anch("for...of 陳述式")}}</li> +</ul> + +<h2 id="for_陳述式"><code>for </code>陳述式</h2> + +<p>一個<a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for">for迴圈</a>不斷重複直到一個指定的條件式判斷為false。JavaScript的for迴圈跟Java還有C的for迴圈很相似。一個for陳述式看起來像下面這樣:</p> + +<pre class="syntaxbox">for ([初始表達式]; [條件式]; [遞增表達式]) + 陳述式 +</pre> + +<p>當執行一個for迴圈時,會發生以下:</p> + +<ol> + <li>如果有的話,初始表達式會被執行。這個表達式通常會初始化一或多個迴圈計數器,但是語法允許任何程度的複雜性。這個表達式也能用來宣告變數。</li> + <li>條件式會被評估。如果評估出的值為true,迴圈的敘事式便會執行。如果評估出的值為false,這個for迴圈便會中止。如果條件式被省略了,狀態就會被假設是true。</li> + <li>執行敘事式。要執行多個敘事式時,使用區塊敘事式(<code>{ ... }</code>) 來把那些敘事式歸為一組。</li> + <li>如果有更新表達式的遞增表達式便執行。然後return到第二步。</li> +</ol> + +<h3 id="範例"><strong>範例</strong></h3> + +<p>以下的函式包含一個用來數在一個滾動列表中被選過的選項(a {{HTMLElement("select")}} 允許複數選項的元素)的for陳述式 。這個for敘事式宣告了變數 i 並將其初始化為0。 他檢查 i ,如果 i 少於在<select>元素中的選項數量,進行接著的 if陳述式,並將 i 在每次通過迴圈後遞增。</p> + +<pre class="brush: html"><form name="selectForm"> + <p> + <label for="musicTypes">Choose some music types, then click the button below:</label> + <select id="musicTypes" name="musicTypes" multiple="multiple"> + <option selected="selected">R&B</option> + <option>Jazz</option> + <option>Blues</option> + <option>New Age</option> + <option>Classical</option> + <option>Opera</option> + </select> + </p> + <p><input id="btn" type="button" value="How many are selected?" /></p> +</form> + +<script> +function howMany(selectObject) { + var numberSelected = 0; + for (var i = 0; i < selectObject.options.length; i++) { + if (selectObject.options[i].selected) { + numberSelected++; + } + } + return numberSelected; +} + +var btn = document.getElementById("btn"); +btn.addEventListener("click", function(){ + alert('Number of options selected: ' + howMany(document.selectForm.musicTypes)) +}); +</script> + +</pre> + +<h2 id="do...while_陳述式"><code>do...while</code> 陳述式</h2> + +<p><code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> </code><code>陳述式會不斷重複直到一個特定的條件判斷為false。一個do...while 陳述式看起來像以下:</code></p> + +<pre class="syntaxbox">do + 陳述式 +while (條件式); +</pre> + +<p><code>陳述式會在檢查條件式以前先執行一次。要執行多個陳述式的話,使用區塊陳述式來將那些陳述式歸為一組。如果條件式為true,那陳述式便再次執行。在每次執行的最後,條件會被檢查。當條件式為false時,</code> 停止執行並把控制傳給 <code>do...while接著的陳述式。</code></p> + +<h3 id="範例_2"><strong>範例</strong></h3> + +<p>在下列範例中,do迴圈重複了至少一次並不斷重複直到 i 不再比 5 少。</p> + +<pre class="brush: js">var i = 0; +do { + i += 1; + console.log(i); +} while (i < 5);</pre> + +<h2 id="while_陳述式"><code>while</code> 陳述式</h2> + +<p><code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/while">while</a></code> 陳述式會不斷執行它的陳述式只要指定的條件式判斷為true。一個while陳述式看起來如下:</p> + +<pre class="syntaxbox">while (condition) + statement +</pre> + +<p>如果條件式變成 false ,在迴圈中的陳述式會停止執行並控制交給跟在這個迴圈後面的陳述式。</p> + +<p>條件式的測試發生於迴圈內的陳述式執行之前。如果條件式傳回 true ,陳述式便會被執行而判斷式會再被測試一次。如果條件式傳回 false ,停止執行並把控制交給跟在 while 迴圈後面的陳述式。</p> + +<p><code>要執行多個陳述式的話,使用區塊陳述式來將那些陳述式歸為一組。</code></p> + +<h3 id="範例_1"><strong>範例 1</strong></h3> + +<p>以下的while迴圈在只要n比3少的情況下便會不斷重複:</p> + +<pre class="brush: js">var n = 0; +var x = 0; +while (n < 3) { + n++; + x += n; +} +</pre> + +<p>在每次的疊代,迴圈把 n 遞增並將其值加到 x 上。因此,x 跟 n 的值會是下列情況:</p> + +<ul> + <li>經過第一次迴圈後 <code>n</code> = 1 而 <code>x</code> = 1</li> + <li>經過第二次迴圈後 <code>n</code> = 2 而 <code>x</code> = 3</li> + <li>經過第三次迴圈後 <code>n</code> = 3 而 <code>x</code> = 6</li> +</ul> + +<p>在完成第三次迴圈後,判斷是 n<3 不再是 true ,所以迴圈終止。</p> + +<h3 id="範例_2_2"><strong>範例 2</strong></h3> + +<p>避免無限迴圈。確定在迴圈內的判斷式終究會變成 false; 不然迴圈會永遠不終止。在迴圈內的陳述式會永遠的執行因為判斷式永遠不會變成false:</p> + +<pre class="brush: js">while (true) { + console.log("Hello, world"); +}</pre> + +<h2 id="label_陳述式"><code>label</code> 陳述式</h2> + +<p> <a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/label">label</a> 提供一個有識別字的陳述式讓你能在程式的別的地方參考。舉個例子,你能使用label 來識別一個迴圈,然後使用break或continue陳述式來指示何時程式該中斷迴圈或是繼續他的執行。</p> + +<p>label 陳述式的語法看起來如下:</p> + +<pre class="syntaxbox">label : + statement +</pre> + +<p>Label的值可以是任何不是保留字的JavaScript識別字。你用label所識別的陳述式可以是任何陳述式。</p> + +<h3 id="範例_3"><strong>範例</strong></h3> + +<p>在這個範例,<code>markLoop這個label 識別一個while 迴圈。</code></p> + +<pre class="brush: js">markLoop: +while (theMark == true) { + doSomething(); +}</pre> + +<h2 id="break_陳述式"><code>break</code> 陳述式</h2> + +<p><code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/break">break</a></code> 陳述式是用來終止一個迴圈,一個switch多重控制選項,或是和一個label陳述式聯合使用。</p> + +<ul> + <li>當你在沒有label的情況下使用break,它會馬上終止最內部的 while , do-while , for ,或是 switch 區間並將控制交給接下來的陳述式。</li> + <li>當你跟label一起使用的時候,它會終止那個特定的被label的陳述式。</li> +</ul> + +<p>break 陳述式的語法看起來如下:</p> + +<ol> + <li><code>break;</code></li> + <li><code>break <em>label</em>;</code></li> +</ol> + +<p>第一種語法會終止最內部的迴圈或switch區間;第二種語法會終止那個特定的label陳述式。</p> + +<h3 id="範例_1_2"><strong>範例</strong> <strong>1</strong></h3> + +<p>以下的範例會不斷重複跑迴圈直到有在陣列裡的元素符合 theValue 的值:</p> + +<pre class="brush: js">for (var i = 0; i < a.length; i++) { + if (a[i] == theValue) { + break; + } +}</pre> + +<h3 id="範例_2_Break至一個label陳述式"><strong>範例 2: </strong>Break至一個label陳述式</h3> + +<pre class="brush: js">var x = 0; +var z = 0; +labelCancelLoops: while (true) { + console.log("Outer loops: " + x); + x += 1; + z = 1; + while (true) { + console.log("Inner loops: " + z); + z += 1; + if (z === 10 && x === 10) { + break labelCancelLoops; + } else if (z === 10) { + break; + } + } +} +</pre> + +<h2 id="continue_陳述式"><code>continue</code> 陳述式</h2> + +<p><code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/continue">continue</a></code> 陳述式可以用於重新開始一個 while , do-while, for, 或 label 陳述式。</p> + +<ul> + <li>當你在沒有label的情況下使用continue,它會終止現在最內部while, do-while , for陳述式區間的迭代並繼續執行該迴圈的下一個迭代。跟break陳述式不同的是,continue不會把整個迴圈的執行給終止。在while 迴圈中,它會跳回條件式的判斷。在for迴圈中,它會跳至遞增陳述式。</li> + <li>當contunue跟label一起使用的時候,它會應用至被label識別的那個迴圈陳述式。</li> +</ul> + +<p>continue 陳述式的語法看起來如下:</p> + +<ol> + <li><code>continue;</code></li> + <li><code>continue </code><em><code>label;</code></em></li> +</ol> + +<h3 id="範例_1_3"><strong>範例 1</strong></h3> + +<p>以下的範例有while迴圈以及一個在 i 的值為 3 的時候執行的continue陳述式。因此,n的值會連著是 1, 3, 7, 12。</p> + +<pre class="brush: js">var i = 0; +var n = 0; +while (i < 5) { + i++; + if (i == 3) { + continue; + } + n += i; +} +</pre> + +<h3 id="範例_2_3"><strong>範例 2</strong></h3> + +<p>一個被label成 checkiandj 的陳述式包還著一個被label成 checkj 的陳述式。如果遇到了continue,程式會終止現在的這輪迴圈並開始下一輪。每次遇到continue,checkj就會一直重複直到它的條件式返回false。當false被傳回時,checkiandj 陳述式剩下的陳述式已被完成,而checkiandj 也會繼續重複直到它的條件式傳回 false。當false被傳回,程式會繼續進行接著checkiandj後面的陳述式。</p> + +<p>如果continue有了checkiandj的label 程式會從checkiandj陳述式的頭開始繼續。</p> + +<pre class="brush: js">checkiandj: + while (i < 4) { + console.log(i); + i += 1; + checkj: + while (j > 4) { + console.log(j); + j -= 1; + if ((j % 2) == 0) { + continue checkj; + } + console.log(j + " is odd."); + } + console.log("i = " + i); + console.log("j = " + j); + }</pre> + +<h2 id="for...in_陳述式"><code>for...in</code> 陳述式</h2> + +<p><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for...in"><code>for...in</code></a> 陳述式重複一個指定的變數來循環一個物件所有可枚舉的屬性。至於每個獨特的屬性,JavaScript執行特定的陳述式。一個<code>for...in</code> 陳述式看起來像以下:</p> + +<pre class="syntaxbox">for (variable in object) { + statements +} +</pre> + +<h3 id="範例_4"><strong>範例</strong></h3> + +<p>以下的函式透過它的參數得到一個物件和物件的名字。接著它循環這個物件的所有屬性並傳回一個列出屬性名和值的字串。</p> + +<pre class="brush: js">function dump_props(obj, obj_name) { + var result = ""; + for (var i in obj) { + result += obj_name + "." + i + " = " + obj[i] + "<br>"; + } + result += "<hr>"; + return result; +} +</pre> + +<p>對於一個擁有make跟model屬性的物件 car來說,執行結果是:</p> + +<pre class="brush: js">car.make = Ford +car.model = Mustang +</pre> + +<h3 id="陣列"><strong>陣列</strong></h3> + +<p>雖然用for...in來迭代 {{jsxref("Array")}} 元素很吸引人,但是它傳回的除了數字的索引之外還有可能是你自己定的屬性名。因此還是用帶有數字索引的傳統<code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for">for</a>迴圈來迭帶一個陣列會比較好。因為如果你想改變陣列物件,比如增加屬性或是方法,</code><strong>for...in</strong> 陳述式迭代的是自定的屬性而不是陣列的元素。</p> + +<h2 id="for...of_陳述式"><code>for...of</code> 陳述式</h2> + +<p> <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for...of">for...of</a></code> 陳述式在<a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/iterable">iterable objects</a>(可迭代的物件)上建立了一個循環 (包含 {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments">arguments</a>(參數) 物件 等等), 對每個獨特屬性的值使用一個準備被執行的有陳述式的自訂迭代掛勾。</p> + +<pre class="syntaxbox">for (<em>variable</em> of <em>object</em>) { + <em>statement +</em>}</pre> + +<p>下列的範例可看出<code>for...of</code> 迴圈跟 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for...in" title="en-US/docs/JavaScript/Reference/Statements/for...in">for...in</a></code> 迴圈的差別。 <code>for...in</code> 在屬性名字循環,而<code>for...of</code> 在屬性的值循環。</p> + +<pre class="brush:js">let arr = [3, 5, 7]; +arr.foo = "hello"; + +for (let i in arr) { + console.log(i); // logs "0", "1", "2", "foo" +} + +for (let i of arr) { + console.log(i); // logs 3, 5, 7 +} +</pre> + +<p>{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</p> diff --git a/files/zh-tw/web/javascript/guide/numbers_and_dates/index.html b/files/zh-tw/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..88ed75fd3e --- /dev/null +++ b/files/zh-tw/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,383 @@ +--- +title: 數字與日期 +slug: Web/JavaScript/Guide/Numbers_and_dates +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</div> + +<p class="summary">這個章節將介紹如何在 JavaScript 中處理數字與日期。</p> + +<h2 id="數字Numbers">數字(Numbers)</h2> + +<p>在 JavaScript 中, Number所使用的標準依照 <a class="external external-icon" href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">double-precision 64-bit binary format IEEE 754</a> (i.e. number的區間是 -(2<sup>53</sup> -1) 到 2<sup>53</sup> -1)。<strong>整數是沒有特定的類型</strong>。</p> + +<p>此外還可以顯示浮點數,三種符號數值: <code>+</code>{{jsxref("Infinity")}}, <code>-</code>{{jsxref("Infinity")}}, and {{jsxref("NaN")}} (not-a-number)。</p> + +<p>{{jsxref("BigInt")}} 是Javascript最新的功能,它可以表示一個很大的整數。使用 <code>BigInt需要注意一點</code>,<code>BigInt</code> 和{{jsxref("Number")}}不能在同一個operation混用還有當用 {{jsxref("Math")}} 物件時不能使用<code>BigInt</code>。</p> + +<p>請參照 <a href="/en-US/docs/Web/JavaScript/Data_structures">JavaScript data types and structures</a> 來取得更多詳細資料。</p> + +<p>你可以用四種進制表示數字:十進制 (decimal),二進制 (binary),八進制 (octal) 以及十六進制 (hexadecimal)。</p> + +<h3 id="十進制數值">十進制數值</h3> + +<pre class="brush: js notranslate">1234567890 +42 + +// 以零為開頭時要小心: + +0888 // 888 解析為 十進制數值 +0777 // 在 non-strict 模式下將解析成八進制 (等同於十進制的 511) +</pre> + +<p>請注意,十進位數字允許第一個數字設為零(<code>0</code>)的話,前提是後面接的數字必須要有一個數字大於8(例如輸入0888結果會是888,輸入068結果會是68),不然則會被轉成8進位(例如0777結果會是511,輸入063結果會是51)。</p> + +<h3 id="二進制數值">二進制數值</h3> + +<p>二進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「B」 (<code>0b</code> 或 <code>0B</code>)。如果 <code>0b</code> 後面接著的數字不是 0 或 1,那會丟出 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError(語法錯誤)</a></code>: "Missing binary digits after 0b"。</p> + +<pre class="brush: js notranslate">var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648 +var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040 +var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607</pre> + +<h3 id="八進制數值">八進制數值</h3> + +<p>八進制數值以 0 為開頭。如果 <code>0</code> 後面的數字超出 0 到 7 這個範圍,將會被解析成十進制數值。</p> + +<pre class="brush: js notranslate">var n = 0755; // 493 +var m = 0644; // 420 +</pre> + +<p>Strict mode in ECMAScript 5 forbids octal syntax. Octal syntax isn't part of ECMAScript 5, but it's supported in all browsers by prefixing the octal number with a zero: <code>0644 === 420</code> and<code>"\045" === "%"</code>. In ECMAScript 2015, octal numbers are supported if they are prefixed with <code>0o</code>, e.g.: </p> + +<pre class="brush: js notranslate">var a = 0o10; // ES2015: 8 +</pre> + +<h3 id="十六進制數值">十六進制數值</h3> + +<p>十六進制數值以 0 為開頭並跟著一個大寫或小寫的英文字母 「X」(<code>0x</code> 或 <code>0X</code>)。如果 <code>0b</code> 後面接著的值超出範圍 (0123456789ABCDEF),那會丟出 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError(語法錯誤)</a></code>:"Identifier starts immediately after numeric literal"。</p> + +<pre class="brush: js notranslate">0xFFFFFFFFFFFFFFFFF // 295147905179352830000 +0x123456789ABCDEF // 81985529216486900 +0XA // 10 +</pre> + +<h3 id="指數運算">指數運算</h3> + +<pre class="brush: js notranslate">1E3 // 1000 +2e6 // 2000000 +0.1e2 // 10</pre> + +<h2 id="Number_物件"><code>Number</code> 物件</h2> + +<p>The built-in {{jsxref("Number")}} object has properties for numerical constants, such as maximum value, not-a-number, and infinity. You cannot change the values of these properties and you use them as follows:</p> + +<pre class="brush: js notranslate">var biggestNum = Number.MAX_VALUE; +var smallestNum = Number.MIN_VALUE; +var infiniteNum = Number.POSITIVE_INFINITY; +var negInfiniteNum = Number.NEGATIVE_INFINITY; +var notANum = Number.NaN; +</pre> + +<p>You always refer to a property of the predefined <code>Number</code> object as shown above, and not as a property of a <code>Number</code> object you create yourself.</p> + +<p>下面這張表格整理了 <code>Number</code> 物件的屬性</p> + +<p><code style="font-weight: 700;">Number</code><strong style="font-style: inherit; font-weight: 700;"> 的屬性</strong></p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">屬性</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.MAX_VALUE")}}</td> + <td>可表示的最大數值</td> + </tr> + <tr> + <td>{{jsxref("Number.MIN_VALUE")}}</td> + <td>可表示的最小數值</td> + </tr> + <tr> + <td>{{jsxref("Number.NaN")}}</td> + <td>表示「非數值」(Not-A-Number)的數值</td> + </tr> + <tr> + <td>{{jsxref("Number.NEGATIVE_INFINITY")}}</td> + <td>Special negative infinite value; returned on overflow</td> + </tr> + <tr> + <td>{{jsxref("Number.POSITIVE_INFINITY")}}</td> + <td>Special positive infinite value; returned on overflow</td> + </tr> + <tr> + <td>{{jsxref("Number.EPSILON")}}</td> + <td>Difference between one and the smallest value greater than one that can be represented as a {{jsxref("Number")}}.</td> + </tr> + <tr> + <td>{{jsxref("Number.MIN_SAFE_INTEGER")}}</td> + <td>可以在 JavaScript 中安全表示的最小數值。</td> + </tr> + <tr> + <td>{{jsxref("Number.MAX_SAFE_INTEGER")}}</td> + <td>可以在 JavaScript 中安全表示的最大數值。</td> + </tr> + </tbody> +</table> + +<table class="standard-table"> + <caption><code>Number</code> 的方法</caption> + <thead> + <tr> + <th>方法</th> + <th>描述</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.parseFloat()")}}</td> + <td>字串轉換成浮點數。<br> + 等同於全域函式 {{jsxref("parseFloat", "parseFloat()")}} 。</td> + </tr> + <tr> + <td>{{jsxref("Number.parseInt()")}}</td> + <td>以指定的基數將字串轉換成整數。<br> + 等同於全域函式 {{jsxref("parseInt", "parseInt()")}} 。</td> + </tr> + <tr> + <td>{{jsxref("Number.isFinite()")}}</td> + <td>判定給定的值是不是一個有限數。</td> + </tr> + <tr> + <td>{{jsxref("Number.isInteger()")}}</td> + <td>判定給定的值是不是一個整數</td> + </tr> + <tr> + <td>{{jsxref("Number.isNaN()")}}</td> + <td>Determines whether the passed value is {{jsxref("Global_Objects/NaN", "NaN")}}. More robust version of the original global {{jsxref("Global_Objects/isNaN", "isNaN()")}}.</td> + </tr> + <tr> + <td>{{jsxref("Number.isSafeInteger()")}}</td> + <td>Determines whether the provided value is a number that is a <dfn>safe integer</dfn>.</td> + </tr> + </tbody> +</table> + +<p>The <code>Number</code> prototype provides methods for retrieving information from <code>Number</code> objects in various formats. The following table summarizes the methods of <code>Number.prototype</code>.</p> + +<table class="standard-table"> + <caption><code>Number.prototype</code> 的方法</caption> + <thead> + <tr> + <th scope="col">方法</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.toExponential", "toExponential()")}}</td> + <td>Returns a string representing the number in exponential notation.</td> + </tr> + <tr> + <td>{{jsxref("Number.toFixed", "toFixed()")}}</td> + <td>Returns a string representing the number in fixed-point notation.</td> + </tr> + <tr> + <td>{{jsxref("Number.toPrecision", "toPrecision()")}}</td> + <td>Returns a string representing the number to a specified precision in fixed-point notation.</td> + </tr> + </tbody> +</table> + +<h2 id="Math_物件"><code>Math</code> 物件</h2> + +<p>The built-in {{jsxref("Math")}} object has properties and methods for mathematical constants and functions. For example, the <code>Math</code> object's <code>PI</code> property has the value of pi (3.141...), which you would use in an application as</p> + +<pre class="brush: js notranslate">Math.PI +</pre> + +<p>Similarly, standard mathematical functions are methods of <code>Math</code>. These include trigonometric, logarithmic, exponential, and other functions. For example, if you want to use the trigonometric function sine, you would write</p> + +<pre class="brush: js notranslate">Math.sin(1.56) +</pre> + +<p>Note that all trigonometric methods of <code>Math</code> take arguments in radians.</p> + +<p>The following table summarizes the <code>Math</code> object's methods.</p> + +<table class="standard-table"> + <caption><code>Math</code> 的方法</caption> + <thead> + <tr> + <th scope="col">方法</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Math.abs", "abs()")}}</td> + <td>絕對值</td> + </tr> + <tr> + <td>{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}}</td> + <td>三角函數; 引數以弳度表示</td> + </tr> + <tr> + <td>{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}}</td> + <td>反三角函數; 回傳值以弳度表示</td> + </tr> + <tr> + <td>{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}}</td> + <td>雙曲函數; 引數以 hyperbolic angle 表示</td> + </tr> + <tr> + <td>{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}}</td> + <td>反雙曲函數; 回傳值以 hyperbolic angle 表示</td> + </tr> + <tr> + <td> + <p>{{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}}</p> + </td> + <td>指數及對數函式</td> + </tr> + <tr> + <td>{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}}</td> + <td>回傳小於等於/大於等於指定數字的最大/最小整數</td> + </tr> + <tr> + <td>{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}}</td> + <td>Returns lesser or greater (respectively) of comma separated list of numbers arguments</td> + </tr> + <tr> + <td>{{jsxref("Math.random", "random()")}}</td> + <td>回傳一個介於 0 到 1 之間的數值</td> + </tr> + <tr> + <td>{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}},</td> + <td>Rounding and truncation functions.</td> + </tr> + <tr> + <td>{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}}</td> + <td>Square root, cube root, Square root of the sum of square arguments.</td> + </tr> + <tr> + <td>{{jsxref("Math.sign", "sign()")}}</td> + <td>The sign of a number, indicating whether the number is positive, negative or zero.</td> + </tr> + <tr> + <td>{{jsxref("Math.clz32", "clz32()")}},<br> + {{jsxref("Math.imul", "imul()")}}</td> + <td>Number of leading zero bits in the 32-bit binary representation.<br> + The result of the C-like 32-bit multiplication of the two arguments.</td> + </tr> + </tbody> +</table> + +<p>Unlike many other objects, you never create a <code>Math</code> object of your own. You always use the built-in <code>Math</code> object.</p> + +<h2 id="Date_物件"><code>Date</code> 物件</h2> + +<p>JavaScript 沒有所謂日期(date)的數據型態(data type)。你可以使用 {{jsxref("Date")}} 物件及其方法去設定日期跟時間來滿足你的需求 。<code>Date</code> 物件有大量的設定取得操作日期的方法(method),但它沒有屬性。</p> + +<p>JavaScript 處理日期的方式跟Java類似。這兩個語言有許多一樣的date方法,且都將日期儲存為從1970年1月1號0時0分0秒以來的毫秒數(millisecond)。</p> + +<p><code>Date</code> 物件範圍是 -100,000,000 days to 100,000,000 days 以1970年1月1號0時0分0秒UTC為基準。</p> + +<p>創建一個<code>Date</code>物件:</p> + +<pre class="brush: js notranslate">var dateObjectName = new Date([parameters]); +</pre> + +<p>在這裡創建一個名為<code>dateObjectName</code> 的 <code>Date</code> 物件;它可以是一個新的物件或是某個以存在的物件當中的屬性。</p> + +<p>Calling <code>Date</code> without the <code>new</code> keyword returns a string representing the current date and time.</p> + +<p>The <code>parameters</code> in the preceding syntax can be any of the following:</p> + +<ul> + <li>Nothing: creates today's date and time. For example, <code>today = new Date();</code>.</li> + <li>A string representing a date in the following form: "Month day, year hours:minutes:seconds." For example, <code>var Xmas95 = new Date("December 25, 1995 13:30:00")</code>. If you omit hours, minutes, or seconds, the value will be set to zero.</li> + <li>A set of integer values for year, month, and day. For example, <code>var Xmas95 = new Date(1995, 11, 25)</code>.</li> + <li>A set of integer values for year, month, day, hour, minute, and seconds. For example, <code>var Xmas95 = new Date(1995, 11, 25, 9, 30, 0);</code>.</li> +</ul> + +<h3 id="Date_的方法"> <code>Date</code> 的方法</h3> + +<p>The <code>Date</code> object methods for handling dates and times fall into these broad categories:</p> + +<ul> + <li>"set" methods, for setting date and time values in <code>Date</code> objects.</li> + <li>"get" methods, for getting date and time values from <code>Date</code> objects.</li> + <li>"to" methods, for returning string values from <code>Date</code> objects.</li> + <li>parse and UTC methods, for parsing <code>Date</code> strings.</li> +</ul> + +<p>With the "get" and "set" methods you can get and set seconds, minutes, hours, day of the month, day of the week, months, and years separately. There is a <code>getDay</code> method that returns the day of the week, but no corresponding <code>setDay</code> method, because the day of the week is set automatically. These methods use integers to represent these values as follows:</p> + +<ul> + <li>Seconds and minutes: 0 到 59</li> + <li>Hours: 0 到 23</li> + <li>Day: 0 (星期日) 到 6 (星期六)</li> + <li>Date: 1 到 31 (這個月的第幾天)</li> + <li>Months: 0 (一月) 到 11 (十二月)</li> + <li>Year: years since 1900</li> +</ul> + +<p>舉例,假設你定義了一個日期如下:</p> + +<pre class="brush: js notranslate">var Xmas95 = new Date('December 25, 1995'); +</pre> + +<p>那 <code>Xmas95.getMonth()</code> 將會回傳 11, <code>Xmas95.getFullYear()</code> 會回傳 1995。</p> + +<p><code>getTime</code> 及 <code>setTime</code> 這兩個方法對於比較日期有幫助。 The <code>getTime</code> method returns the number of milliseconds since January 1, 1970, 00:00:00 for a <code>Date</code> object.</p> + +<p>For example, the following code displays the number of days left in the current year:</p> + +<pre class="brush: js notranslate">var today = new Date(); +var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Set day and month +endYear.setFullYear(today.getFullYear()); // Set year to this year +var msPerDay = 24 * 60 * 60 * 1000; // Number of milliseconds per day +var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay; +var daysLeft = Math.round(daysLeft); //returns days left in the year +</pre> + +<p>This example creates a <code>Date</code> object named <code>today</code> that contains today's date. It then creates a <code>Date</code> object named <code>endYear</code> and sets the year to the current year. Then, using the number of milliseconds per day, it computes the number of days between <code>today</code> and <code>endYear</code>, using <code>getTime</code> and rounding to a whole number of days.</p> + +<p>The <code>parse</code> method is useful for assigning values from date strings to existing <code>Date</code> objects. For example, the following code uses <code>parse</code> and <code>setTime</code> to assign a date value to the <code>IPOdate</code> object:</p> + +<pre class="brush: js notranslate">var IPOdate = new Date(); +IPOdate.setTime(Date.parse('Aug 9, 1995')); +</pre> + +<h3 id="範例">範例</h3> + +<p>下面這個範例,<code>JSClock()</code> 這個函式將會以數位時鐘的格式回傳時間。</p> + +<pre class="brush: js notranslate">function JSClock() { + var time = new Date(); + var hour = time.getHours(); + var minute = time.getMinutes(); + var second = time.getSeconds(); + var temp = '' + ((hour > 12) ? hour - 12 : hour); + if (hour == 0) + temp = '12'; + temp += ((minute < 10) ? ':0' : ':') + minute; + temp += ((second < 10) ? ':0' : ':') + second; + temp += (hour >= 12) ? ' P.M.' : ' A.M.'; + return temp; +} +</pre> + +<p> <code>JSClock</code> 這個函式會先建立一個名為 <code>time</code> 的 <code>Date</code> 物件; 因為沒有提供任何引數,所以會放入目前的日期及時間。接著呼叫 <code>getHours</code> 、 <code>getMinutes</code> 以及 <code>getSeconds</code> 這三個方法將現在的時、分以及秒分別指定給 <code>hour</code> 、 <code>minute</code> 以及 <code>second</code> 這三個變數。</p> + +<p>接著的四行指令將會建立一個時間的字串。第一行的指令建立了一個變數 <code>temp</code>,以條件運算式指定值; 如果 <code>hour</code> 大於 12,那就指定 (<code>hour - 12</code>),不然會直接指定 <code>hour</code>, 但如果 <code>hour</code> 等於 0 , 則改為 12。</p> + +<p>接著下一行將 <code>minute</code> 加到 <code>temp</code> 中。如果 <code>minute</code> 小於 10, 則會在附加時補上一個零; 不然的話會直接加上冒號及分鐘數。秒數也是以同樣的作法附加到 <code>temp</code> 上。</p> + +<p>最後,判斷 <code>hour</code> 是不是大於等於 12 ,如果是就在 <code>temp</code> 加上 "P.M." ,不然就加上 "A.M."。</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</p> diff --git a/files/zh-tw/web/javascript/guide/regular_expressions/index.html b/files/zh-tw/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..f9b4235c2a --- /dev/null +++ b/files/zh-tw/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,700 @@ +--- +title: 正規表達式 +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - Guide + - JavaScript + - RegExp + - 正規表達式 +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</p> + +<p>正規表達式是被用來匹配字串中字元組合的模式。在 JavaScript 中,正規表達式也是物件,這些模式在 {{jsxref("RegExp")}} 的 {{jsxref("RegExp.exec", "exec")}} 和 {{jsxref("RegExp.test", "test")}} 方法中,以及 {{jsxref("String")}} 的 {{jsxref("String.match", "match")}}、{{jsxref("String.replace", "replace")}}、{{jsxref("String.search", "search")}}、{{jsxref("String.split", "split")}} 等方法中被運用。這一章節將解說 JavaScript 中的正規表達式。</p> + +<h2 id="建立正規表達式">建立正規表達式</h2> + +<p>您可透過下列兩種方法去創建一條正規表達式:</p> + +<p>使用正規表達式字面值(regular expression literal),包含兩個 <code>/</code> 字元之間的模式如下:</p> + +<pre>var re = /ab+c/; +</pre> + +<p>正規表達式字面值在 script 載入時會被編譯,當正規表達式為定值時,使用此方法可獲得較佳效能。</p> + +<p>或呼叫 {{jsxref("RegExp")}} 物件的建構函式,如下:</p> + +<pre>var re = new RegExp('ab+c'); +</pre> + +<p>使用建構子函數供即時編譯正則表達式,當模式會異動、事先未知匹配模式、或者您將從其他地方取得時,使用建構子函數將較為合適。</p> + +<h2 id="撰寫正規表達模式">撰寫正規表達模式</h2> + +<p>正規表達模式由數個簡易字元組成,例如 <code>/abc/</code>,或是由簡易字元及特殊符號組合而成,例如 <code>/ab*c/</code>、<code>/Chapter (\d+)\.\d*/ )</code>。最後一個範例用到了括號,這在正規表達式中用作記憶組,使用括號的匹配將會被留到後面使用,在 {{ web.link("#Using_Parenthesized_Substring_Matches", "使用帶括號的配對子字串 Using Parenthesized Substring Matches") }} 有更多解釋。</p> + +<h3 id="使用簡易模式">使用簡易模式</h3> + +<p>簡易的模式是有你找到的直接匹配所構成的。比如:<code>/abc/</code> 這個模式就匹配了在一個字符串中,僅僅字符 <code>'abc'</code> 同時出現並按照這個順序。這兩個句子中「<em>Hi, do you know your abc's?</em>」和「<em>The latest airplane designs evolved from slabcraft.</em>」就會匹配成功。在上面的兩個實例中,匹配的是子字符串 'abc'。在字符串中的 "Grab crab"('ab c') 中將不會被匹配,因為它不包含任何的 'abc' 字符串。</p> + +<h3 id="使用特殊字元">使用特殊字元</h3> + +<p>當你需要搜尋一個比直接匹配需要更多條件的匹配,比如搜尋一或多個 'b',或者搜尋空格,那麼這個模式將要包含特殊字符。例如: 模式 <code>/ab*c/</code> 匹配了一個單獨的 'a' 後面跟了零或多個 'b'(* 的意思是前面一項出現了零或多個),且後面跟著 'c' 的任何字符組合。在字符串 "cbbabbbbcdebc" 中,這個模式匹配了子字符串 "abbbbc"。</p> + +<p>下面的表格列出了在正則表達式中可以利用的特殊字符完整列表以及描述。</p> + +<table class="standard-table"> + <caption>正則表達式中的特殊字元</caption> + <thead> + <tr> + <th scope="col">字元</th> + <th scope="col">解說</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="#special-backslash" id="special-backslash" name="special-backslash"><code>\</code></a></td> + <td> + <p>反斜線放在非特殊符號前面,使非特殊符號不會被逐字譯出,代表特殊作用。<br> + 例如:'b' 如果沒有 '\' 在前頭,功能是找出小寫 b;若改為 '\b' 則代表的是邊界功能,block 用意。<br> + /\bter\b/.test("interest") //false<br> + /\bter\b/.test("in ter est") //true<br> + <br> + <code>/a*/</code> 找出0個或是1個以上的a;而 /a\*/ 找出 'a*' 這個字串<br> + /aaaa*/g.test("caaady") //true<br> + /a\*/.test("caaady") //false<br> + <br> + '\' 也能使自身表現出來,表現 '\' ,必須以 '\\' 表達。<br> + /[\\]/.test(">\\<") //true</p> + </td> + </tr> + <tr> + <td><a href="#special-caret" id="special-caret" name="special-caret"><code>^</code></a></td> + <td> + <p>匹配輸入的開頭,如果 multiline flag 被設為 true,則會匹配換行字元後。</p> + + <p>例如:<code>/^A/</code> 不會匹配「an A」的 A,但會匹配「An E」中的 A。</p> + + <p>「<code>^</code>」出現在字元集模式的字首中有不同的意思,詳見<a href="#special-negated-character-set" title="#special-negated-character-set">補字元集</a>。</p> + </td> + </tr> + <tr> + <td><a href="#special-dollar" id="special-dollar" name="special-dollar"><code>$</code></a></td> + <td> + <p>匹配輸入的結尾,如果 multiline flag 被設為 true,則會匹配換行字元。</p> + + <p>例如:<code>/t$/</code> 不會匹配「eater」中的 t,卻會匹配「eat」中的 t。</p> + </td> + </tr> + <tr> + <td><a href="#special-asterisk" id="special-asterisk" name="special-asterisk"><code>*</code></a></td> + <td> + <p>匹配前一字元 0 至多次。<br> + <br> + 下面舉例要求基本 'aaaa' ,'a*' 後面有0個或多個a的意思<br> + /aaaaa*/g.test("caaady") //false</p> + + <p>例如:<code>/bo*/</code> 匹配「A ghost booooed」中的 boooo、「A bird warbled」中的 b,但在「A goat grunted」中不會匹配任何字串。</p> + </td> + </tr> + <tr> + <td><a href="#special-plus" id="special-plus" name="special-plus"><code>+</code></a></td> + <td> + <p>匹配前一字元 1 至多次,等同於 <code>{1,}</code>。</p> + + <p>例如:<code>/a+/</code> 匹配「candy」中的 a,以及所有「caaaaaaandy」中的 a。</p> + </td> + </tr> + <tr> + <td><a href="#special-questionmark" id="special-questionmark" name="special-questionmark"><code>?</code></a></td> + <td> + <p>匹配前一字元 0 至 1 次,等同於 <code>{0,1}</code>。</p> + + <p>例如:<code>/e?le?/</code> 匹配「angel」中的 el、「angle」中的 le、以及「oslo」中的 l。</p> + + <p>如果是使用在 <code>*</code>、<code>+</code>、<code>?</code> 或 <code>{}</code> 等 quantifier 之後,將會使這些 quantifier non-greedy(也就是儘可能匹配最少的字元),與此相對的是 greedy(匹配儘可能多的字元)。例如:在「123abc」中應用 <code>/\d+/</code> 可匹配「123」,但使用 <code>/\d+?/</code> 在相同字串上只能匹配「1」。</p> + + <p><br> + Also used in lookahead assertions, as described in the <code>x(?=y)</code> and <code>x(?!y)</code> entries of this table.</p> + </td> + </tr> + <tr> + <td><a href="#special-dot" id="special-dot" name="special-dot"><code>.</code></a></td> + <td> + <p>(小數點)匹配除了換行符號之外的單一字元。</p> + + <p>例如:/.n/ 匹配「nay, an apple is on the tree」中的 an 和 on,但在「nay」中沒有匹配。</p> + </td> + </tr> + <tr> + <td><a href="#special-capturing-parentheses" id="special-capturing-parentheses" name="special-capturing-parentheses"><code>(x)</code></a></td> + <td> + <p>Capturing Parentheses</p> + + <p>匹配 'x' 並記住此次的匹配,如下面的範例所示。</p> + + <p>在 正則表達示 /(foo) (bar) \1 \2/ 中的 (foo) 與 (bar) 可匹配了 "foo bar foo bar" 這段文字中的前兩個字,而 \1 與 \2 則匹配了後面的兩個字。注意, \1, \2, ..., \n 代表的就是前面的pattern,以本範例來說,/(foo) (bar) \1 \2/ 等同於 /(foo) (bar) (foo) (bar)/。</p> + + <p>用於取代(replace)的話,則是用 $1, $2,...,$n。如 'bar boo'.replace(/(...) (...)/, '$2 $1').<br> + <code>$&</code> means the whole matched string.</p> + </td> + </tr> + <tr> + <td><a href="#special-non-capturing-parentheses" id="special-non-capturing-parentheses" name="special-non-capturing-parentheses"><code>(?:x)</code></a></td> + <td> + <p><em>Non-Capturing Parentheses</em></p> + + <p>找出 'x',這動作不會記憶<br> + <code>()</code>為 group 的意思,檢查時會再 wrap 一次,若有 <code>g</code> flag 會無效,<br> + <code>?:</code> 代表只要 group 就好,不要 wrap</p> + + <p>有無 <code>()</code> 差別 ?<br> + <code>'foo'.match(/(foo)/) </code><br> + <code>// ['foo', 'foo', index: 0, input: 'foo' ]<br> + 'foo'.match(/foo/)<br> + // [ 'foo', index: 0, input: 'foo' ]</code></p> + + <p> 有無<code>?:</code>差別?<br> + <code>'foo'.match(/(foo){1,2}/)<br> + // [ 'foo', 'foo', index: 0, input: 'foo' ]<br> + 'foo'.match(/(?:foo){1,2}/)<br> + [ 'foo', index: 0, input: 'foo' ]</code><br> + 連<code>()</code>都沒有,則<code>{1,2}</code>只是適用在<code>foo</code>的第二個<code>o</code>的條件而已。</p> + + <p>更多資訊詳見 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Using_parentheses">Using parentheses</a> 。</p> + </td> + </tr> + <tr> + <td><a href="#special-lookahead" id="special-lookahead" name="special-lookahead"><code>x(?=y)</code></a></td> + <td> + <p>符合'x',且後接的是'y'。'y'為'x'存在的意義。<br> + <br> + 例如:<code>/Jack(?=Sprat)/,</code>在後面是Sprat的存在下,Jack才有意義。<br> + <code>/Jack(?=Sprat|Frost)/</code>後面是Sprat「或者是」Frost的存在下,Jack才有意義。但我們要找的目標是Jack,後面的條件都只是filter/條件的功能而已。</p> + </td> + </tr> + <tr> + <td><a href="#special-negated-look-ahead" id="special-negated-look-ahead" name="special-negated-look-ahead"><code>x(?!y)</code></a></td> + <td> + <p>符合'x',且後接的不是'y'。'y'為否定'x'存在的意義,後面不行前功盡棄(negated lookahead)。<br> + <br> + 例如: <code>/\d+(?!\.)/</code> ,要找一個或多個數字時,在後面接的不是「點」的情況下成立。<br> + <br> + <code>var result = /\d+(?!\.)/.exec("3.141")</code> ,<br> + result執行出來為[ '141', index: 2, input: '3.141'],<br> + index:2,代表141從index = 2開始。</p> + </td> + </tr> + <tr> + <td><a href="#special-or" id="special-or" name="special-or"><code>x|y</code></a></td> + <td> + <p>符合「x」或「y」。</p> + + <p>舉例來說,<code>/green|red/</code> 的話,會匹配 <code>"green apple"</code> 中的 <code>"green"</code> 以及 <code>"red apple."</code> 的 <code>"red"</code> 。</p> + </td> + </tr> + <tr> + <td><a href="#special-quantifier" id="special-quantifier" name="special-quantifier"><code>{n}</code></a></td> + <td> + <p>規定符號確切發生的次數,n為正整數</p> + + <p>例如:<code>/a{2}/</code>無法在 "candy" 找到、但 "caandy" 行;若字串擁有2個以上 "caaandy" 還是只會認前面2個。</p> + </td> + </tr> + <tr> + <td><a href="#special-quantifier-range" id="special-quantifier-range" name="special-quantifier-range"><code>{n,m}</code></a></td> + <td> + <p>搜尋條件:n為至少、m為至多,其n、m皆為正整數。若把m設定為0,則為Invalid regular expression。</p> + + <p>例如:<code>/a{1,3}/ </code>無法在 "cndy" 匹配到;而在 "candy" 中的第1個"a"符合;在 "caaaaaaandy" 中的前3個 "aaa" 符合,雖然此串有許多a,但只認前面3個。</p> + </td> + </tr> + <tr> + <td><a href="#special-character-set" id="special-character-set" name="special-character-set"><code>[xyz]</code></a></td> + <td>字元的集合。此格式會匹配中括號內所有字元, including <a href="https://developer.mozilla.org/zh-TW/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences">escape sequences</a>。特殊字元,例如點(<code>.</code>) 和米字號(<code>*</code>),在字元集合中不具特殊意義,所以不需轉換。若要設一個字元範圍的集合,可以使用橫線 <code>"-"</code> ,如下例所示:<br> + <br> + <code>[a-d] </code>等同於 <code>[abcd]。</code>會匹配 "brisket" 的 "b" 、"city" 的 'c' ……等。 而<code>/[a-z.]+/ </code>和 <code>/[\w.]+/</code> 均可匹配字串 "test.i.ng" 。</td> + </tr> + <tr> + <td><a href="#special-negated-character-set" id="special-negated-character-set" name="special-negated-character-set"><code>[^xyz]</code></a></td> + <td> + <p>bracket中寫入的字元將被否定,匹配非出現在bracket中的符號。<br> + 可用 '-' 來界定字元的範圍。一般直接表達的符號都可以使用這種方式。</p> + + <p><code>[^abc]</code>可以寫作[^<code>a-c]</code>. "brisket" 中找到 'r' 、"chop."中找到 'h'。</p> + </td> + </tr> + <tr> + <td><a href="#special-backspace" id="special-backspace" name="special-backspace"><code>[\b]</code></a></td> + <td>吻合倒退字元 (U+0008). (不會跟 \b 混淆)</td> + </tr> + <tr> + <td><a href="#special-word-boundary" id="special-word-boundary" name="special-word-boundary"><code>\b</code></a></td> + <td> + <p>吻合文字邊界。A word boundary matches the position where a word character is not followed or preceded by another word-character. Note that a matched word boundary is not included in the match. In other words, the length of a matched word boundary is zero. (Not to be confused with <code>[\b]</code>.)</p> + + <p>Examples:<br> + <code>/\bm/</code> matches the 'm' in "moon" ;<br> + <code>/oo\b/</code> does not match the 'oo' in "moon", because 'oo' is followed by 'n' which is a word character;<br> + <code>/oon\b/</code> matches the 'oon' in "moon", because 'oon' is the end of the string, thus not followed by a word character;<br> + <code>/\w\b\w/</code> will never match anything, because a word character can never be followed by both a non-word and a word character.</p> + + <p><strong>Note:</strong> JavaScript's regular expression engine defines a <a href="http://www.ecma-international.org/ecma-262/5.1/#sec-15.10.2.6">specific set of characters</a> to be "word" characters. Any character not in that set is considered a word break. This set of characters is fairly limited: it consists solely of the Roman alphabet in both upper- and lower-case, decimal digits, and the underscore character. Accented characters, such as "é" or "ü" are, unfortunately, treated as word breaks.</p> + </td> + </tr> + <tr> + <td><a href="#special-non-word-boundary" id="special-non-word-boundary" name="special-non-word-boundary"><code>\B</code></a></td> + <td> + <p>吻合非文字邊界。This matches a position where the previous and next character are of the same type: Either both must be words, or both must be non-words. The beginning and end of a string are considered non-words.</p> + + <p>For example, <code>/\B../</code> matches 'oo' in "noonday", and <code>/y\B./</code> matches 'ye' in "possibly yesterday."</p> + </td> + </tr> + <tr> + <td><a href="#special-control" id="special-control" name="special-control"><code>\c<em>X</em></code></a></td> + <td> + <p>Where <em>X</em> is a character ranging from A to Z. Matches a control character in a string.</p> + + <p>For example, <code>/\cM/</code> matches control-M (U+000D) in a string.</p> + </td> + </tr> + <tr> + <td><a href="#special-digit" id="special-digit" name="special-digit"><code>\d</code></a></td> + <td> + <p>吻合數字,寫法等同於 <code>[0-9] 。</code></p> + + <p>例如:<code>/\d/</code> 或 <code>/[0-9]/</code> 在 "B2 is the suite number." 中找到 '2'</p> + </td> + </tr> + <tr> + <td><a href="#special-non-digit" id="special-non-digit" name="special-non-digit"><code>\D</code></a></td> + <td> + <p>吻合非數字,寫法等同於 <code>[^0-9]。</code></p> + + <p>例如:<code>/\D/</code> 或<code>/[^0-9]/</code> 在 "B2 is the suite number." 中找到 'B' 。</p> + </td> + </tr> + <tr> + <td><code><a href="#special-form-feed" id="special-form-feed" name="special-form-feed">\f</a></code></td> + <td>Matches a form feed (U+000C).</td> + </tr> + <tr> + <td><a href="#special-line-feed" id="special-line-feed" name="special-line-feed"><code>\n</code></a></td> + <td>Matches a line feed (U+000A).</td> + </tr> + <tr> + <td><a href="#special-carriage-return" id="special-carriage-return" name="special-carriage-return"><code>\r</code></a></td> + <td>Matches a carriage return (U+000D).</td> + </tr> + <tr> + <td><a href="#special-white-space" id="special-white-space" name="special-white-space"><code>\s</code></a></td> + <td> + <p>Matches a single white space character, including space, tab, form feed, line feed. Equivalent to <code>[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>.</p> + + <p>For example, <code>/\s\w*/</code> matches ' bar' in "foo bar."</p> + </td> + </tr> + <tr> + <td><a href="#special-non-white-space" id="special-non-white-space" name="special-non-white-space"><code>\S</code></a></td> + <td> + <p>Matches a single character other than white space. Equivalent to <code>[^ \f\n\r\t\v\u00a0\\u1680u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]</code>.</p> + + <p>For example, <code>/\S\w*/</code> matches 'foo' in "foo bar."</p> + </td> + </tr> + <tr> + <td><a href="#special-tab" id="special-tab" name="special-tab"><code>\t</code></a></td> + <td>Matches a tab (U+0009).</td> + </tr> + <tr> + <td><a href="#special-vertical-tab" id="special-vertical-tab" name="special-vertical-tab"><code>\v</code></a></td> + <td>Matches a vertical tab (U+000B).</td> + </tr> + <tr> + <td><a href="#special-word" id="special-word" name="special-word"><code>\w</code></a></td> + <td> + <p>包含數字字母與底線,等同於<code>[A-Za-z0-9_]。</code></p> + + <p>例如: <code>/\w/</code> 符合 'apple'中的 'a' 、'$5.28中的 '5' 以及 '3D' 中的 '3'。</p> + + <p>For example, <code>/\w/</code> matches 'a' in "apple," '5' in "$5.28," and '3' in "3D."</p> + </td> + </tr> + <tr> + <td><a href="#special-non-word" id="special-non-word" name="special-non-word"><code>\W</code></a></td> + <td> + <p>Matches any non-word character. Equivalent to <code>[^A-Za-z0-9_]</code>.</p> + + <p>For example, <code>/\W/</code> or <code>/[^A-Za-z0-9_]/</code> matches '%' in "50%."</p> + </td> + </tr> + <tr> + <td><a href="#special-backreference" id="special-backreference" name="special-backreference"><code>\<em>n</em></code></a></td> + <td> + <p>Where <em>n</em> is a positive integer, a back reference to the last substring matching the <em>n</em> parenthetical in the regular expression (counting left parentheses).</p> + + <p>For example, <code>/apple(,)\sorange\1/</code> matches 'apple, orange,' in "apple, orange, cherry, peach."</p> + </td> + </tr> + <tr> + <td><a href="#special-null" id="special-null" name="special-null"><code>\0</code></a></td> + <td>Matches a NULL (U+0000) character. Do not follow this with another digit, because <code>\0<digits></code> is an octal <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences">escape sequence</a>. Instead use <code>\x00</code>.</td> + </tr> + <tr> + <td><a href="#special-hex-escape" id="special-hex-escape" name="special-hex-escape"><code>\xhh</code></a></td> + <td>Matches the character with the code hh (two hexadecimal digits)</td> + </tr> + <tr> + <td><a href="#special-unicode-escape" id="special-unicode-escape" name="special-unicode-escape"><code>\uhhhh</code></a></td> + <td>Matches the character with the code hhhh (four hexadecimal digits).</td> + </tr> + </tbody> +</table> + +<p>Escaping user input that is to be treated as a literal string within a regular expression—that would otherwise be mistaken for a special character—can be accomplished by simple replacement:</p> + +<pre>function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} +</pre> + +<p>The g after the regular expression is an option or flag that performs a global search, looking in the whole string and returning all matches. It is explained in detail below in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags">Advanced Searching With Flags</a>.</p> + +<h3 id="使用括號">使用括號 </h3> + +<p>Parentheses around any part of the regular expression pattern causes that part of the matched substring to be remembered. Once remembered, the substring can be recalled for other use, as described in {{ web.link("#Using_parenthesized_substring_matches", "Using Parenthesized Substring Matches") }}.</p> + +<p>For example, the pattern <code>/Chapter (\d+)\.\d*/</code> illustrates additional escaped and special characters and indicates that part of the pattern should be remembered. It matches precisely the characters 'Chapter ' followed by one or more numeric characters (<code>\d</code> means any numeric character and <code>+</code> means 1 or more times), followed by a decimal point (which in itself is a special character; preceding the decimal point with \ means the pattern must look for the literal character '.'), followed by any numeric character 0 or more times (<code>\d</code> means numeric character, <code>*</code> means 0 or more times). In addition, parentheses are used to remember the first matched numeric characters.</p> + +<p>This pattern is found in "Open Chapter 4.3, paragraph 6" and '4' is remembered. The pattern is not found in "Chapter 3 and 4", because that string does not have a period after the '3'.</p> + +<p>To match a substring without causing the matched part to be remembered, within the parentheses preface the pattern with <code>?:</code>. For example, <code>(?:\d+)</code> matches one or more numeric characters but does not remember the matched characters.</p> + +<h2 id="運用正規表達式">運用正規表達式</h2> + +<p>Regular expressions are used with the <code>RegExp</code> methods <code>test</code> and <code>exec</code> and with the <code>String</code> methods <code>match</code>, <code>replace</code>, <code>search</code>, and <code>split</code>. These methods are explained in detail in the <a href="/en-US/docs/Web/JavaScript/Reference" title="en-US/docs/JavaScript/Reference">JavaScript reference</a>.</p> + +<table class="standard-table"> + <caption>Methods that use regular expressions</caption> + <thead> + <tr> + <th scope="col">Method</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("RegExp.exec", "exec")}}</td> + <td>A <code>RegExp</code> method that executes a search for a match in a string. It returns an array of information or null on a mismatch.</td> + </tr> + <tr> + <td>{{jsxref("RegExp.test", "test")}}</td> + <td>A <code>RegExp</code> method that tests for a match in a string. It returns true or false.</td> + </tr> + <tr> + <td>{{jsxref("String.match", "match")}}</td> + <td>A <code>String</code> method that executes a search for a match in a string. It returns an array of information or null on a mismatch.</td> + </tr> + <tr> + <td>{{jsxref("String.search", "search")}}</td> + <td>A <code>String</code> method that tests for a match in a string. It returns the index of the match, or -1 if the search fails.</td> + </tr> + <tr> + <td>{{jsxref("String.replace", "replace")}}</td> + <td>A <code>String</code> method that executes a search for a match in a string, and replaces the matched substring with a replacement substring.</td> + </tr> + <tr> + <td>{{jsxref("String.split", "split")}}</td> + <td>A <code>String</code> method that uses a regular expression or a fixed string to break a string into an array of substrings.</td> + </tr> + </tbody> +</table> + +<p>When you want to know whether a pattern is found in a string, use the <code>test</code> or <code>search</code> method; for more information (but slower execution) use the <code>exec</code> or <code>match</code> methods. If you use <code>exec</code> or <code>match</code> and if the match succeeds, these methods return an array and update properties of the associated regular expression object and also of the predefined regular expression object, <code>RegExp</code>. If the match fails, the <code>exec</code> method returns <code>null</code> (which coerces to <code>false</code>).</p> + +<p>In the following example, the script uses the <code>exec</code> method to find a match in a string.</p> + +<pre>var myRe = /d(b+)d/g; +var myArray = myRe.exec('cdbbdbsbz'); +</pre> + +<p>If you do not need to access the properties of the regular expression, an alternative way of creating <code>myArray</code> is with this script:</p> + +<pre>var myArray = /d(b+)d/g.exec('cdbbdbsbz'); // similar to "cdbbdbsbz".match(/d(b+)d/g); however, + // the latter outputs Array [ "dbbd" ], while + // /d(b+)d/g.exec('cdbbdbsbz') outputs Array [ "dbbd", "bb" ]. + // See below for further info (CTRL+F "The behavior associated with the".)</pre> + +<p>If you want to construct the regular expression from a string, yet another alternative is this script:</p> + +<pre>var myRe = new RegExp('d(b+)d', 'g'); +var myArray = myRe.exec('cdbbdbsbz'); +</pre> + +<p>With these scripts, the match succeeds and returns the array and updates the properties shown in the following table.</p> + +<table class="standard-table"> + <caption>Results of regular expression execution.</caption> + <thead> + <tr> + <th scope="col">物件</th> + <th scope="col">Property or index</th> + <th scope="col">說明</th> + <th scope="col">範例</th> + </tr> + </thead> + <tbody> + <tr> + <td rowspan="4"><code>myArray</code></td> + <td></td> + <td>The matched string and all remembered substrings.</td> + <td><code>['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']</code></td> + </tr> + <tr> + <td><code>index</code></td> + <td>The 0-based index of the match in the input string.</td> + <td><code>1</code></td> + </tr> + <tr> + <td><code>input</code></td> + <td>The original string.</td> + <td><code>"cdbbdbsbz"</code></td> + </tr> + <tr> + <td><code>[0]</code></td> + <td>The last matched characters.</td> + <td><code>"dbbd"</code></td> + </tr> + <tr> + <td rowspan="2"><code>myRe</code></td> + <td><code>lastIndex</code></td> + <td>The index at which to start the next match. (This property is set only if the regular expression uses the g option, described in {{ web.link("#Advanced_searching_with_flags", "Advanced Searching With Flags") }}.)</td> + <td><code>5</code></td> + </tr> + <tr> + <td><code>source</code></td> + <td>The text of the pattern. Updated at the time that the regular expression is created, not executed.</td> + <td><code>"d(b+)d"</code></td> + </tr> + </tbody> +</table> + +<p>As shown in the second form of this example, you can use a regular expression created with an object initializer without assigning it to a variable. If you do, however, every occurrence is a new regular expression. For this reason, if you use this form without assigning it to a variable, you cannot subsequently access the properties of that regular expression. For example, assume you have this script:</p> + +<pre>var myRe = /d(b+)d/g; +var myArray = myRe.exec('cdbbdbsbz'); +console.log('The value of lastIndex is ' + myRe.lastIndex); + +// "The value of lastIndex is 5" +</pre> + +<p>However, if you have this script:</p> + +<pre>var myArray = /d(b+)d/g.exec('cdbbdbsbz'); +console.log('The value of lastIndex is ' + /d(b+)d/g.lastIndex); + +// "The value of lastIndex is 0" +</pre> + +<p>The occurrences of <code>/d(b+)d/g</code> in the two statements are different regular expression objects and hence have different values for their <code>lastIndex</code> property. If you need to access the properties of a regular expression created with an object initializer, you should first assign it to a variable.</p> + +<h3 id="Using_Parenthesized_Substring_Matches">Using Parenthesized Substring Matches</h3> + +<p>Including parentheses in a regular expression pattern causes the corresponding submatch to be remembered. For example, <code>/a(b)c/</code> matches the characters 'abc' and remembers 'b'. To recall these parenthesized substring matches, use the <code>Array</code> elements <code>[1]</code>, ..., <code>[n]</code>.</p> + +<p>The number of possible parenthesized substrings is unlimited. The returned array holds all that were found. The following examples illustrate how to use parenthesized substring matches.</p> + +<p>下面這個 script 以 {{jsxref("String.replace", "replace()")}} 方法移轉字串位置。對於要被置換的文字內容,以 <code>$1</code> 和 <code>$2</code> 來代表先前 re 這個變數裡面,找出來綑綁且照順序來表示兩個子字串。</p> + +<pre>var re = /(\w+)\s(\w+)/; +var str = 'John Smith'; +var newstr = str.replace(re, '$2, $1'); +console.log(newstr); + +// "Smith, John" +</pre> + +<h3 id="Advanced_Searching_With_Flags">Advanced Searching With Flags</h3> + +<p>Regular expressions have five optional flags that allow for global and case insensitive searching. These flags can be used separately or together in any order, and are included as part of the regular expression.</p> + +<table class="standard-table"> + <caption>Regular expression flags</caption> + <thead> + <tr> + <th scope="col">Flag</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>g</code></td> + <td>Global search.</td> + </tr> + <tr> + <td>i</td> + <td>Case-insensitive search.</td> + </tr> + <tr> + <td>m</td> + <td>Multi-line search.</td> + </tr> + <tr> + <td>u</td> + <td>unicode; treat a pattern as a sequence of unicode code points</td> + </tr> + <tr> + <td>y</td> + <td>Perform a "sticky" search that matches starting at the current position in the target string. See {{jsxref("RegExp.sticky", "sticky")}}</td> + </tr> + </tbody> +</table> + +<p>To include a flag with the regular expression, use this syntax:</p> + +<pre>var re = /pattern/flags; +</pre> + +<p>or</p> + +<pre>var re = new RegExp('pattern', 'flags'); +</pre> + +<p>Note that the flags are an integral part of a regular expression. They cannot be added or removed later.</p> + +<p>For example, <code>re = /\w+\s/g</code> creates a regular expression that looks for one or more characters followed by a space, and it looks for this combination throughout the string.</p> + +<pre>var re = /\w+\s/g; +var str = 'fee fi fo fum'; +var myArray = str.match(re); +console.log(myArray); + +// ["fee ", "fi ", "fo "] +</pre> + +<p>You could replace the line:</p> + +<pre>var re = /\w+\s/g; +</pre> + +<p>with:</p> + +<pre>var re = new RegExp('\\w+\\s', 'g'); +</pre> + +<p>and get the same result.</p> + +<p>The behavior associated with the '<strong><code>g</code></strong>' flag is different when the <code>.exec()</code> method is used. (The roles of "class" and "argument" get reversed: In the case of <code>.match()</code>, the string class (or data type) owns the method and the regular expression is just an argument, while in the case of <code>.exec()</code>, it is the regular expression that owns the method, with the string being the argument. Contrast <em><code>str.match(re)</code></em> versus <em><code>re.exec(str)</code></em>.) The '<code><strong>g</strong></code>' flag is used with the <strong><code>.exec()</code></strong> method to get iterative progression.</p> + +<pre>var xArray; while(xArray = re.exec(str)) console.log(xArray); +// produces: +// ["fee ", index: 0, input: "fee fi fo fum"] +// ["fi ", index: 4, input: "fee fi fo fum"] +// ["fo ", index: 7, input: "fee fi fo fum"]</pre> + +<p>The <code>m</code> flag is used to specify that a multiline input string should be treated as multiple lines. If the <code>m</code> flag is used, <code>^</code> and <code>$</code> match at the start or end of any line within the input string instead of the start or end of the entire string.</p> + +<h2 id="範例">範例</h2> + +<p>The following examples show some uses of regular expressions.</p> + +<h3 id="Changing_the_order_in_an_input_string">Changing the order in an input string</h3> + +<p>The following example illustrates the formation of regular expressions and the use of <code>string.split()</code> and <code>string.replace()</code>. It cleans a roughly formatted input string containing names (first name last) separated by blanks, tabs and exactly one semicolon. Finally, it reverses the name order (last name first) and sorts the list.</p> + +<pre>// The name string contains multiple spaces and tabs, +// and may have multiple spaces between first and last names. +var names = 'Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand '; + +var output = ['---------- Original String\n', names + '\n']; + +// Prepare two regular expression patterns and array storage. +// Split the string into array elements. + +// pattern: possible white space then semicolon then possible white space +var pattern = /\s*;\s*/; + +// Break the string into pieces separated by the pattern above and +// store the pieces in an array called nameList +var nameList = names.split(pattern); + +// new pattern: one or more characters then spaces then characters. +// Use parentheses to "memorize" portions of the pattern. +// The memorized portions are referred to later. +pattern = /(\w+)\s+(\w+)/; + +// Below is the new array for holding names being processed. +var bySurnameList = []; + +// Display the name array and populate the new array +// with comma-separated names, last first. +// +// The replace method removes anything matching the pattern +// and replaces it with the memorized string—the second memorized portion +// followed by a comma, a space and the first memorized portion. +// +// The variables $1 and $2 refer to the portions +// memorized while matching the pattern. + +output.push('---------- After Split by Regular Expression'); + +var i, len; +for (i = 0, len = nameList.length; i < len; i++) { + output.push(nameList[i]); + bySurnameList[i] = nameList[i].replace(pattern, '$2, $1'); +} + +// Display the new array. +output.push('---------- Names Reversed'); +for (i = 0, len = bySurnameList.length; i < len; i++) { + output.push(bySurnameList[i]); +} + +// Sort by last name, then display the sorted array. +bySurnameList.sort(); +output.push('---------- Sorted'); +for (i = 0, len = bySurnameList.length; i < len; i++) { + output.push(bySurnameList[i]); +} + +output.push('---------- End'); + +console.log(output.join('\n')); +</pre> + +<h3 id="使用特殊字元驗證輸入">使用特殊字元驗證輸入</h3> + +<p>In the following example, the user is expected to enter a phone number. When the user presses the "Check" button, the script checks the validity of the number. If the number is valid (matches the character sequence specified by the regular expression), the script shows a message thanking the user and confirming the number. If the number is invalid, the script informs the user that the phone number is not valid.</p> + +<p>Within non-capturing parentheses <code>(?:</code> , the regular expression looks for three numeric characters <code>\d{3}</code> OR <code>|</code> a left parenthesis <code>\(</code> followed by three digits<code> \d{3}</code>, followed by a close parenthesis <code>\)</code>, (end non-capturing parenthesis <code>)</code>), followed by one dash, forward slash, or decimal point and when found, remember the character <code>([-\/\.])</code>, followed by three digits <code>\d{3}</code>, followed by the remembered match of a dash, forward slash, or decimal point <code>\1</code>, followed by four digits <code>\d{4}</code>.</p> + +<p>The <code>Change</code> event activated when the user presses Enter sets the value of <code>RegExp.input</code>.</p> + +<pre><!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <meta http-equiv="Content-Script-Type" content="text/javascript"> + <script type="text/javascript"> + var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/; + function testInfo(phoneInput) { + var OK = re.exec(phoneInput.value); + if (!OK) + window.alert(phoneInput.value + ' isn\'t a phone number with area code!'); + else + window.alert('Thanks, your phone number is ' + OK[0]); + } + </script> + </head> + <body> + <p>Enter your phone number (with area code) and then click "Check". + <br>The expected format is like ###-###-####.</p> + <form action="#"> + <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button> + </form> + </body> +</html> +</pre> + +<p>{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</p> diff --git a/files/zh-tw/web/javascript/guide/using_promises/index.html b/files/zh-tw/web/javascript/guide/using_promises/index.html new file mode 100644 index 0000000000..1df6376ffd --- /dev/null +++ b/files/zh-tw/web/javascript/guide/using_promises/index.html @@ -0,0 +1,256 @@ +--- +title: 使用 Promise +slug: Web/JavaScript/Guide/Using_promises +translation_of: Web/JavaScript/Guide/Using_promises +--- +<div>{{jsSidebar("JavaScript Guide")}}</div> + +<p>{{jsxref("Promise")}} 是一個表示非同步運算的最終完成或失敗的物件。由於多數人使用預建立的 Promise,這個導覽會先講解回傳 Promise 的使用方式,之後再介紹如何建立。</p> + +<p>基本上,一個 Promise 是一個根據附加給他的 Callback 回傳的物件,以取代傳遞 Callback 到這個函數。</p> + +<p>舉例來說,下方的範例若用舊方式應該會有兩個 Callback,並根據成功或失敗來決定使用哪個:</p> + +<pre class="brush: js line-numbers language-js">function successCallback(result) { + console.log("It succeeded with " + result); +} + +function failureCallback(error) { + console.log("It failed with " + error); +} + +doSomething(successCallback, failureCallback); +</pre> + +<p>而新作法會回傳一個 Promise,這樣你就可以附加 Callback:</p> + +<pre class="brush: js line-numbers language-js">let promise = doSomething(); +promise.then(successCallback, failureCallback);</pre> + +<p>再簡單點:</p> + +<pre class="brush: js line-numbers language-js">doSomething().then(successCallback, failureCallback);</pre> + +<p>我們稱之為 <em>非同步函數呼叫</em>。這個做法有許多好處,我們接下來看看。</p> + +<h2 id="保證">保證</h2> + +<p>不如舊做法,一個 Promise 有這些保證:</p> + +<ul> + <li>Callback 不會在<a href="/zh-TW/docs/Web/JavaScript/EventLoop#Run-to-completion">當次的迴圈運行結束</a>前呼叫。</li> + <li>Callback 用 .then 添加,在非同步運算結束<em>後</em>呼叫,像前面那樣。</li> + <li>複 Callback 可以透過重複呼叫 .then 達成。</li> +</ul> + +<p>但 Promise 主要的立即好處是串連。</p> + +<h2 id="串連">串連</h2> + +<p>有個常見的需求是依序呼叫兩個以上的非同步函數,我們稱之為建立 <em>Promise 鏈</em>。</p> + +<p>看看魔術:<code>then</code> 函數回傳一個新的 Promise,不同於原本。</p> + +<pre class="brush: js">let promise = doSomething(); +let promise2 = promise.then(successCallback, failureCallback); +</pre> + +<p>或</p> + +<pre class="brush: js">let promise2 = doSomething().then(successCallback, failureCallback); +</pre> + +<p>第二個 Promise 不只代表 <code>doSomething()</code> 完成,還有<code>successCallback</code> 或 <code>failureCallback</code> ,這兩個非同步函數回傳另一個 Promise。如此一來,任何 Callback 附加給 <code>promise2</code> 會被排在 <code>successCallback</code> 或<code>failureCallback</code> 之後。</p> + +<p>基本上,每個 Promise 代表著鏈中另外一個非同步函數的完成。</p> + +<p>在古時候,多個非同步函數會使用 Callback 方式,導致波動拳問題:</p> + +<p><em>(原文 Pyramid of Doom 查無中文翻譯,以較常見之波動拳取代)</em></p> + +<pre class="brush: js">doSomething(function(result) { + doSomethingElse(result, function(newResult) { + doThirdThing(newResult, function(finalResult) { + console.log('Got the final result: ' + finalResult); + }, failureCallback); + }, failureCallback); +}, failureCallback); +</pre> + +<p>有了新方法,我們附加 Callback 到回傳的 Promise 上,來製造<em> Promise 鏈</em>:</p> + +<pre class="brush: js">doSomething().then(function(result) { + return doSomethingElse(result); +}) +.then(function(newResult) { + return doThirdThing(newResult); +}) +.then(function(finalResult) { + console.log('Got the final result: ' + finalResult); +}) +.catch(failureCallback); +</pre> + +<p><code>then</code> 的函數是選用的,以及 <code>catch(failureCallback)</code> 是 <code>then(null, failureCallback)</code> 的簡寫。你也許會想用<a href="/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭頭函數</a>取代:</p> + +<pre class="brush: js">doSomething() +.then(result => doSomethingElse(result)) +.then(newResult => doThirdThing(newResult)) +.then(finalResult => { + console.log(`Got the final result: ${finalResult}`); +}) +.catch(failureCallback); +</pre> + +<p><strong>注意:</strong>永遠要回傳結果,否則 Callback 不會獲得前一個 Promise 的結果。</p> + +<h3 id="獲錯後串接">獲錯後串接</h3> + +<p>失敗<em>後</em>的串接是可行的,也就是說 <code>catch</code> 會非常好用,即使鏈中出錯。看看這個範例:</p> + +<pre class="brush: js">new Promise((resolve, reject) => { + console.log('Initial'); + + resolve(); +}) +.then(() => { + throw new Error('Something failed'); + + console.log('Do this'); +}) +.catch(() => { + console.log('Do that'); +}) +.then(() => { + console.log('Do this whatever happened before'); +}); +</pre> + +<p>他會輸出:</p> + +<pre>Initial +Do that +Do this whatever happened before +</pre> + +<p>注意「Do this」沒有被輸出,因為「Something failed」錯誤導致拒絕。</p> + +<h2 id="錯誤傳遞">錯誤傳遞</h2> + +<p>在波動拳狀況中,你可能會看到三次 <code>failureCallback</code> ,在 Promise 鏈中只需要在尾端使用一次:</p> + +<pre class="brush: js">doSomething() +.then(result => doSomethingElse(result)) +.then(newResult => doThirdThing(newResult)) +.then(finalResult => console.log(`Got the final result: ${finalResult}`)) +.catch(failureCallback); +</pre> + +<p>基本上,一個 Promise 鏈遇到錯誤時會往下尋找 Catch 處理器。這是經過模組化的非同步程式:</p> + +<pre class="brush: js">try { + let result = syncDoSomething(); + let newResult = syncDoSomethingElse(result); + let finalResult = syncDoThirdThing(newResult); + console.log(`Got the final result: ${finalResult}`); +} catch(error) { + failureCallback(error); +} +</pre> + +<p>在 ECMAScript 2017 中,在有 <a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> 語法糖的同步程式達到高峰:</p> + +<pre class="brush: js">async function foo() { + try { + let result = await doSomething(); + let newResult = await doSomethingElse(result); + let finalResult = await doThirdThing(newResult); + console.log(`Got the final result: ${finalResult}`); + } catch(error) { + failureCallback(error); + } +} +</pre> + +<p>這基於 Promise,例如 <code>doSomething()</code>和之前一樣。你可以閱讀在<a href="https://developers.google.com/web/fundamentals/getting-started/primers/async-functions">這裡</a>閱讀更多。</p> + +<p>Promise 藉由捕捉所有錯誤,包含例外和程式錯誤,解決了 Callback 地獄的缺點。這是非同步運算的基本特性。</p> + +<h2 id="在舊有_API_上建立_Promise">在舊有 API 上建立 Promise</h2> + +<p>{{jsxref("Promise")}} 可以透過建構子建立。所以用建構子包裹舊的 API即可。</p> + +<p>在理想情況,所有非同步函數都會回傳 Promise,然而許多 API 仍然用舊的方式來傳遞成功、失敗 Callback,有個典型的例子是{{domxref("WindowTimers.setTimeout", "setTimeout()")}} :</p> + +<pre class="brush: js">setTimeout(() => saySomething("10 seconds passed"), 10000); +</pre> + +<p>混合古代 Callback 和 Promise 是有問題的。如果 <code>saySomething</code> 失敗或有程式錯誤,那不會有任何錯誤被捕捉。</p> + +<p>幸運地,我們可以用 Promise 包裹他,最好盡可能的在最底層包裹,並永遠不要再直接呼叫他們:</p> + +<pre class="brush: js">const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback); +</pre> + +<p>基本上,Promise 建構子需要一個運作函數來正規地處理或拒絕 Promise。但因為 <code>setTimeout</code> 不會失敗,所以我們捨棄 reject。</p> + +<h2 id="組合">組合</h2> + +<p>{{jsxref("Promise.resolve()")}} 和 {{jsxref("Promise.reject()")}} 是用來正規地建立已經處理或拒絕的 Promise。他們在某些情況特別有用。</p> + +<p>{{jsxref("Promise.all()")}} 和 {{jsxref("Promise.race()")}} 是兩個組合工具用於使 Promise 平行運作。</p> + +<p>連續關聯是可行的,這是極簡 JavaScript 範例:</p> + +<pre class="brush: js">[func1, func2].reduce((p, f) => p.then(f), Promise.resolve()); +</pre> + +<p>基本上,我們摺疊(Reduce)一個非同步函數陣列成一個 Promise 鏈:<code>Promise.resolve().then(func1).then(func2);</code></p> + +<p>這可以用可重用的構成函數完成,通常用函數式編程:</p> + +<pre class="brush: js">let applyAsync = (acc,val) => acc.then(val); +let composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));</pre> + +<p><code>composeAsync</code> 接受任何數量的函數作為參數,並回傳一個接受一個初始值用來傳給組合的新函數。這個好處是無論其中函數是非同步或否,都會保證用正確的順序執行:</p> + +<pre class="brush: js">let transformData = composeAsync(func1, asyncFunc1, asyncFunc2, func2); +transformData(data); +</pre> + +<p>ECMAScript 2017 中連續組合利用 async/await 更簡單:</p> + +<pre class="brush: js">for (let f of [func1, func2]) { + await f(); +} +</pre> + +<h2 id="計時">計時</h2> + +<p>為了避免意外,傳給 <code>then</code> 的函數不會被同步地呼叫,即使是完成的 Promise:</p> + +<pre class="brush: js">Promise.resolve().then(() => console.log(2)); +console.log(1); // 1, 2 +</pre> + +<p>被傳入的函數會被放在子任務佇列而非立即執行,因此他會在當前的事件迴圈結束、佇列清空時執行,例如:</p> + +<pre class="brush: js">const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +wait().then(() => console.log(4)); +Promise.resolve().then(() => console.log(2)).then(() => console.log(3)); +console.log(1); // 1, 2, 3, 4 +</pre> + +<h2 id="看更多">看更多</h2> + +<ul> + <li>{{jsxref("Promise.then()")}}</li> + <li><a href="http://promisesaplus.com/">Promises/A+ 特色</a></li> + <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li> + <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c#.dzlqh6ski">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li> + <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</a></li> + <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li> +</ul> diff --git a/files/zh-tw/web/javascript/guide/working_with_objects/index.html b/files/zh-tw/web/javascript/guide/working_with_objects/index.html new file mode 100644 index 0000000000..823f9c1e4b --- /dev/null +++ b/files/zh-tw/web/javascript/guide/working_with_objects/index.html @@ -0,0 +1,499 @@ +--- +title: 物件的使用 +slug: Web/JavaScript/Guide/Working_with_Objects +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</div> + +<p class="summary">JavaScript is designed on a simple object-based paradigm. An object is a collection of properties, and a property is an association between a name (or <em>key</em>) and a value. A property's value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects. This chapter describes how to use objects, properties, functions, and methods, and how to create your own objects.</p> + +<h2 id="物件概觀">"物件"概觀</h2> + +<p>就如同其他程式語言一般,JacaScript裡頭的"物件"可以與真實生活中的物件做類比。其概念可以用生活中有形的物體來做理解。</p> + +<p>在JavaScript裡,"物件"是一個擁有自己的屬性、型別、獨立的實體。這裡我們以杯子舉例:我們可以從顏色、設計、重量、材質等方面來描述他的屬性。同樣的,我們也可以用各種屬性來描述JavaScript中某個物體的特性。</p> + +<h2 id="物件與屬性">物件與屬性</h2> + +<p>JavaScript的物件有其關聯的屬性。物件的屬性可以用附著在物件上的變數來描述。</p> + +<p> Object properties are basically the same as ordinary JavaScript variables, except for the attachment to objects. The properties of an object define the characteristics of the object. You access the properties of an object with a simple dot-notation:</p> + +<pre class="brush: js">objectName.propertyName +</pre> + +<p>Like all JavaScript variables, both the object name (which could be a normal variable) and property name are case sensitive. You can define a property by assigning it a value. For example, let's create an object named <code>myCar</code> and give it properties named <code>make</code>, <code>model</code>, and <code>year</code> as follows:</p> + +<pre class="brush: js">var myCar = new Object(); +myCar.make = 'Ford'; +myCar.model = 'Mustang'; +myCar.year = 1969; +</pre> + +<p>Unassigned properties of an object are {{jsxref("undefined")}} (and not {{jsxref("null")}}).</p> + +<pre class="brush: js">myCar.color; // undefined</pre> + +<p>Properties of JavaScript objects can also be accessed or set using a bracket notation (for more details see <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors">property accessors</a>). Objects are sometimes called <em>associative arrays</em>, since each property is associated with a string value that can be used to access it. So, for example, you could access the properties of the <code>myCar</code> object as follows:</p> + +<pre class="brush: js">myCar['make'] = 'Ford'; +myCar['model'] = 'Mustang'; +myCar['year'] = 1969; +</pre> + +<p>An object property name can be any valid JavaScript string, or anything that can be converted to a string, including the empty string. However, any property name that is not a valid JavaScript identifier (for example, a property name that has a space or a hyphen, or that starts with a number) can only be accessed using the square bracket notation. This notation is also very useful when property names are to be dynamically determined (when the property name is not determined until runtime). Examples are as follows:</p> + +<pre class="brush: js">// four variables are created and assigned in a single go, +// separated by commas +var myObj = new Object(), + str = 'myString', + rand = Math.random(), + obj = new Object(); + +myObj.type = 'Dot syntax'; +myObj['date created'] = 'String with space'; +myObj[str] = 'String value'; +myObj[rand] = 'Random Number'; +myObj[obj] = 'Object'; +myObj[''] = 'Even an empty string'; + +console.log(myObj); +</pre> + +<p>Please note that all keys in the square bracket notation are converted to String type, since objects in JavaScript can only have String type as key type. For example, in the above code, when the key <code>obj </code>is added to the <code>myObj</code>, JavaScript will call the <code>obj.toString()</code> method, and use this result string as the new key.</p> + +<p>You can also access properties by using a string value that is stored in a variable:</p> + +<pre class="brush: js">var propertyName = 'make'; +myCar[propertyName] = 'Ford'; + +propertyName = 'model'; +myCar[propertyName] = 'Mustang'; +</pre> + +<p>You can use the bracket notation with <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a></code> to iterate over all the enumerable properties of an object. To illustrate how this works, the following function displays the properties of the object when you pass the object and the object's name as arguments to the function:</p> + +<pre class="brush: js">function showProps(obj, objName) { + var result = ''; + for (var i in obj) { + // obj.hasOwnProperty() is used to filter out properties from the object's prototype chain + if (obj.hasOwnProperty(i)) { + result += objName + '.' + i + ' = ' + obj[i] + '\n'; + } + } + return result; +} +</pre> + +<p>So, the function call <code>showProps(myCar, "myCar")</code> would return the following:</p> + +<pre class="brush: js">myCar.make = Ford +myCar.model = Mustang +myCar.year = 1969</pre> + +<h2 id="Enumerate_the_properties_of_an_object">Enumerate the properties of an object</h2> + +<p>Starting with <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_5_support_in_Mozilla" title="en-US/docs/JavaScript/ECMAScript 5 support in Mozilla">ECMAScript 5</a>, there are three native ways to list/traverse object properties:</p> + +<ul> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in" title="en-US/docs/JavaScript/Reference/Statements/for...in">for...in</a></code> loops<br> + This method traverses all enumerable properties of an object and its prototype chain</li> + <li>{{jsxref("Object.keys", "Object.keys(o)")}}<br> + This method returns an array with all the own (not in the prototype chain) enumerable properties' names ("keys") of an object <code>o</code>.</li> + <li>{{jsxref("Object.getOwnPropertyNames", "Object.getOwnPropertyNames(o)")}}<br> + This method returns an array containing all own properties' names (enumerable or not) of an object <code>o</code>.</li> +</ul> + +<p>Before ECMAScript 5, there was no native way to list all properties of an object. However, this can be achieved with the following function:</p> + +<pre class="brush: js">function listAllProperties(o) { + var objectToInspect; + var result = []; + + for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) { + result = result.concat(Object.getOwnPropertyNames(objectToInspect)); + } + + return result; +} +</pre> + +<p>This can be useful to reveal "hidden" properties (properties in the prototype chain which are not accessible through the object, because another property has the same name earlier in the prototype chain). Listing accessible properties only can easily be done by removing duplicates in the array.</p> + +<h2 id="Creating_new_objects">Creating new objects</h2> + +<p>JavaScript has a number of predefined objects. In addition, you can create your own objects. You can create an object using an <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">object initializer</a>. Alternatively, you can first create a constructor function and then instantiate an object invoking that function in conjunction with the <code>new</code> operator.</p> + +<h3 id="Using_object_initializers"><a id="Object_initializers" name="Object_initializers">Using object initializers</a></h3> + +<p>In addition to creating objects using a constructor function, you can create objects using an <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">object initializer</a>. Using object initializers is sometimes referred to as creating objects with literal notation. "Object initializer" is consistent with the terminology used by C++.</p> + +<p>The syntax for an object using an object initializer is:</p> + +<pre class="brush: js">var obj = { property_1: value_1, // property_# may be an identifier... + 2: value_2, // or a number... + // ..., + 'property n': value_n }; // or a string +</pre> + +<p>where <code>obj</code> is the name of the new object, each <code>property_<em>i</em></code> is an identifier (either a name, a number, or a string literal), and each <code>value_<em>i</em></code> is an expression whose value is assigned to the <code>property_<em>i</em></code>. The <code>obj</code> and assignment is optional; if you do not need to refer to this object elsewhere, you do not need to assign it to a variable. (Note that you may need to wrap the object literal in parentheses if the object appears where a statement is expected, so as not to have the literal be confused with a block statement.)</p> + +<p>Object initializers are expressions, and each object initializer results in a new object being created whenever the statement in which it appears is executed. Identical object initializers create distinct objects that will not compare to each other as equal. Objects are created as if a call to <code>new Object()</code> were made; that is, objects made from object literal expressions are instances of <code>Object</code>.</p> + +<p>The following statement creates an object and assigns it to the variable <code>x</code> if and only if the expression <code>cond</code> is true:</p> + +<pre class="brush: js">if (cond) var x = {greeting: 'hi there'}; +</pre> + +<p>The following example creates <code>myHonda</code> with three properties. Note that the <code>engine</code> property is also an object with its own properties.</p> + +<pre class="brush: js">var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}; +</pre> + +<p>You can also use object initializers to create arrays. See <a href="/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Array_literals">array literals</a>.</p> + +<h3 id="Using_a_constructor_function">Using a constructor function</h3> + +<p>Alternatively, you can create an object with these two steps:</p> + +<ol> + <li>Define the object type by writing a constructor function. There is a strong convention, with good reason, to use a capital initial letter.</li> + <li>Create an instance of the object with <code>new</code>.</li> +</ol> + +<p>To define an object type, create a function for the object type that specifies its name, properties, and methods. For example, suppose you want to create an object type for cars. You want this type of object to be called <code>car</code>, and you want it to have properties for make, model, and year. To do this, you would write the following function:</p> + +<pre class="brush: js">function Car(make, model, year) { + this.make = make; + this.model = model; + this.year = year; +} +</pre> + +<p>Notice the use of <code>this</code> to assign values to the object's properties based on the values passed to the function.</p> + +<p>Now you can create an object called <code>mycar</code> as follows:</p> + +<pre class="brush: js">var mycar = new Car('Eagle', 'Talon TSi', 1993); +</pre> + +<p>This statement creates <code>mycar</code> and assigns it the specified values for its properties. Then the value of <code>mycar.make</code> is the string "Eagle", <code>mycar.year</code> is the integer 1993, and so on.</p> + +<p>You can create any number of <code>car</code> objects by calls to <code>new</code>. For example,</p> + +<pre class="brush: js">var kenscar = new Car('Nissan', '300ZX', 1992); +var vpgscar = new Car('Mazda', 'Miata', 1990); +</pre> + +<p>An object can have a property that is itself another object. For example, suppose you define an object called <code>person</code> as follows:</p> + +<pre class="brush: js">function Person(name, age, sex) { + this.name = name; + this.age = age; + this.sex = sex; +} +</pre> + +<p>and then instantiate two new <code>person</code> objects as follows:</p> + +<pre class="brush: js">var rand = new Person('Rand McKinnon', 33, 'M'); +var ken = new Person('Ken Jones', 39, 'M'); +</pre> + +<p>Then, you can rewrite the definition of <code>car</code> to include an <code>owner</code> property that takes a <code>person</code> object, as follows:</p> + +<pre class="brush: js">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; +} +</pre> + +<p>To instantiate the new objects, you then use the following:</p> + +<pre class="brush: js">var car1 = new Car('Eagle', 'Talon TSi', 1993, rand); +var car2 = new Car('Nissan', '300ZX', 1992, ken); +</pre> + +<p>Notice that instead of passing a literal string or integer value when creating the new objects, the above statements pass the objects <code>rand</code> and <code>ken</code> as the arguments for the owners. Then if you want to find out the name of the owner of car2, you can access the following property:</p> + +<pre class="brush: js">car2.owner.name +</pre> + +<p>Note that you can always add a property to a previously defined object. For example, the statement</p> + +<pre class="brush: js">car1.color = 'black'; +</pre> + +<p>adds a property <code>color</code> to car1, and assigns it a value of "black." However, this does not affect any other objects. To add the new property to all objects of the same type, you have to add the property to the definition of the <code>car</code> object type.</p> + +<h3 id="Using_the_Object.create_method">Using the <code>Object.create</code> method</h3> + +<p>Objects can also be created using the {{jsxref("Object.create()")}} method. This method can be very useful, because it allows you to choose the prototype object for the object you want to create, without having to define a constructor function.</p> + +<pre class="brush: js">// Animal properties and method encapsulation +var Animal = { + type: 'Invertebrates', // Default value of properties + displayType: function() { // Method which will display type of Animal + console.log(this.type); + } +}; + +// Create new animal type called animal1 +var animal1 = Object.create(Animal); +animal1.displayType(); // Output:Invertebrates + +// Create new animal type called Fishes +var fish = Object.create(Animal); +fish.type = 'Fishes'; +fish.displayType(); // Output:Fishes</pre> + +<h2 id="Inheritance">Inheritance</h2> + +<p>All objects in JavaScript inherit from at least one other object. The object being inherited from is known as the prototype, and the inherited properties can be found in the <code>prototype</code> object of the constructor. See <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a> for more information.</p> + +<h2 id="Indexing_object_properties">Indexing object properties</h2> + +<p>You can refer to a property of an object either by its property name or by its ordinal index. If you initially define a property by its name, you must always refer to it by its name, and if you initially define a property by an index, you must always refer to it by its index.</p> + +<p>This restriction applies when you create an object and its properties with a constructor function (as we did previously with the <code>Car</code> object type) and when you define individual properties explicitly (for example, <code>myCar.color = "red"</code>). If you initially define an object property with an index, such as <code>myCar[5] = "25 mpg"</code>, you subsequently refer to the property only as <code>myCar[5]</code>.</p> + +<p>The exception to this rule is objects reflected from HTML, such as the <code>forms</code> array. You can always refer to objects in these arrays by either their ordinal number (based on where they appear in the document) or their name (if defined). For example, if the second <code><FORM></code> tag in a document has a <code>NAME</code> attribute of "myForm", you can refer to the form as <code>document.forms[1]</code> or <code>document.forms["myForm"]</code> or <code>document.forms.myForm</code>.</p> + +<h2 id="Defining_properties_for_an_object_type">Defining properties for an object type</h2> + +<p>You can add a property to a previously defined object type by using the <code>prototype</code> property. This defines a property that is shared by all objects of the specified type, rather than by just one instance of the object. The following code adds a <code>color</code> property to all objects of type <code>car</code>, and then assigns a value to the <code>color</code> property of the object <code>car1</code>.</p> + +<pre class="brush: js">Car.prototype.color = null; +car1.color = 'black'; +</pre> + +<p>See the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype" title="en-US/docs/JavaScript/Reference/Global Objects/Function/prototype"><code>prototype</code> property</a> of the <code>Function</code> object in the <a href="/en-US/docs/Web/JavaScript/Reference">JavaScript reference</a> for more information.</p> + +<h2 id="Defining_methods">Defining methods</h2> + +<p>A <em>method</em> is a function associated with an object, or, simply put, a method is a property of an object that is a function. Methods are defined the way normal functions are defined, except that they have to be assigned as the property of an object. See also <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">method definitions</a> for more details. An example is:</p> + +<pre class="brush: js">objectName.methodname = function_name; + +var myObj = { + myMethod: function(params) { + // ...do something + } + + // OR THIS WORKS TOO + + myOtherMethod(params) { + // ...do something else + } +}; +</pre> + +<p>where <code>objectName</code> is an existing object, <code>methodname</code> is the name you are assigning to the method, and <code>function_name</code> is the name of the function.</p> + +<p>You can then call the method in the context of the object as follows:</p> + +<pre class="brush: js">object.methodname(params); +</pre> + +<p>You can define methods for an object type by including a method definition in the object constructor function. You could define a function that would format and display the properties of the previously-defined <code>car</code> objects; for example,</p> + +<pre class="brush: js">function displayCar() { + var result = 'A Beautiful ' + this.year + ' ' + this.make + + ' ' + this.model; + pretty_print(result); +} +</pre> + +<p>where <code>pretty_print</code> is a function to display a horizontal rule and a string. Notice the use of <code>this</code> to refer to the object to which the method belongs.</p> + +<p>You can make this function a method of <code>car</code> by adding the statement</p> + +<pre class="brush: js">this.displayCar = displayCar; +</pre> + +<p>to the object definition. So, the full definition of <code>car</code> would now look like</p> + +<pre class="brush: js">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; + this.displayCar = displayCar; +} +</pre> + +<p>Then you can call the <code>displayCar</code> method for each of the objects as follows:</p> + +<pre class="brush: js">car1.displayCar(); +car2.displayCar(); +</pre> + +<h2 id="Using_this_for_object_references">Using <code>this</code> for object references</h2> + +<p>JavaScript has a special keyword, <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/this">this</a></code>, that you can use within a method to refer to the current object. For example, suppose you have a function called <code>validate</code> that validates an object's <code>value</code> property, given the object and the high and low values:</p> + +<pre class="brush: js">function validate(obj, lowval, hival) { + if ((obj.value < lowval) || (obj.value > hival)) { + alert('Invalid Value!'); + } +} +</pre> + +<p>Then, you could call <code>validate</code> in each form element's <code>onchange</code> event handler, using <code>this</code> to pass it the element, as in the following example:</p> + +<pre class="brush: html"><input type="text" name="age" size="3" + onChange="validate(this, 18, 99)"> +</pre> + +<p>In general, <code>this</code> refers to the calling object in a method.</p> + +<p>When combined with the <code>form</code> property, <code>this</code> can refer to the current object's parent form. In the following example, the form <code>myForm</code> contains a <code>Text</code> object and a button. When the user clicks the button, the value of the <code>Text</code> object is set to the form's name. The button's <code>onclick</code> event handler uses <code>this.form</code> to refer to the parent form, <code>myForm</code>.</p> + +<pre class="brush: html"><form name="myForm"> +<p><label>Form name:<input type="text" name="text1" value="Beluga"></label> +<p><input name="button1" type="button" value="Show Form Name" + onclick="this.form.text1.value = this.form.name"> +</p> +</form></pre> + +<h2 id="Defining_getters_and_setters">Defining getters and setters</h2> + +<p>A <a href="/en-US/docs/Web/JavaScript/Reference/Functions/get">getter</a> is a method that gets the value of a specific property. A <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setter</a> is a method that sets the value of a specific property. You can define getters and setters on any predefined core object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.</p> + +<p>The following illustrates how getters and setters could work for a user-defined object <code>o</code>.</p> + +<pre class="brush: js">var o = { + a: 7, + get b() { + return this.a + 1; + }, + set c(x) { + this.a = x / 2; + } +}; + +console.log(o.a); // 7 +console.log(o.b); // 8 +o.c = 50; +console.log(o.a); // 25 +</pre> + +<p>The <code>o</code> object's properties are:</p> + +<ul> + <li><code>o.a</code> — a number</li> + <li><code>o.b</code> — a getter that returns <code>o.a</code> plus 1</li> + <li><code>o.c</code> — a setter that sets the value of <code>o.a</code> to half of the value <code>o.c</code> is being set to</li> +</ul> + +<p>Please note that function names of getters and setters defined in an object literal using "[gs]et <em>property</em>()" (as opposed to <code>__define[GS]etter__</code> ) are not the names of the getters themselves, even though the <code>[gs]et <em>propertyName</em>(){ }</code> syntax may mislead you to think otherwise. To name a function in a getter or setter using the "[gs]et <em>property</em>()" syntax, define an explicitly named function programmatically using <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty" title="en-US/docs/Core JavaScript 1.5 Reference/Global +Objects/Object/defineProperty">Object.defineProperty</a></code> (or the <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineGetter" title="en-US/docs/Core JavaScript 1.5 Reference/Global +Objects/Object/defineGetter">Object.prototype.__defineGetter__</a></code> legacy fallback).</p> + +<p>The following code illustrates how getters and setters can extend the {{jsxref("Date")}} prototype to add a <code>year</code> property to all instances of the predefined <code>Date</code> class. It uses the <code>Date</code> class's existing <code>getFullYear</code> and <code>setFullYear</code> methods to support the <code>year</code> property's getter and setter.</p> + +<p>These statements define a getter and setter for the year property:</p> + +<pre class="brush: js">var d = Date.prototype; +Object.defineProperty(d, 'year', { + get: function() { return this.getFullYear(); }, + set: function(y) { this.setFullYear(y); } +}); +</pre> + +<p>These statements use the getter and setter in a <code>Date</code> object:</p> + +<pre class="brush: js">var now = new Date(); +console.log(now.year); // 2000 +now.year = 2001; // 987617605170 +console.log(now); +// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001 +</pre> + +<p>In principle, getters and setters can be either</p> + +<ul> + <li>defined using <a href="#Object_initializers">object initializers</a>, or</li> + <li>added later to any object at any time using a getter or setter adding method.</li> +</ul> + +<p>When defining getters and setters using <a href="#Object_initializers">object initializers</a> all you need to do is to prefix a getter method with <code>get</code> and a setter method with <code>set</code>. Of course, the getter method must not expect a parameter, while the setter method expects exactly one parameter (the new value to set). For instance:</p> + +<pre class="brush: js">var o = { + a: 7, + get b() { return this.a + 1; }, + set c(x) { this.a = x / 2; } +}; +</pre> + +<p>Getters and setters can also be added to an object at any time after creation using the <code>Object.defineProperties</code> method. This method's first parameter is the object on which you want to define the getter or setter. The second parameter is an object whose property names are the getter or setter names, and whose property values are objects for defining the getter or setter functions. Here's an example that defines the same getter and setter used in the previous example:</p> + +<pre class="brush: js">var o = { a: 0 }; + +Object.defineProperties(o, { + 'b': { get: function() { return this.a + 1; } }, + 'c': { set: function(x) { this.a = x / 2; } } +}); + +o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property +console.log(o.b); // Runs the getter, which yields a + 1 or 6 +</pre> + +<p>Which of the two forms to choose depends on your programming style and task at hand. If you already go for the object initializer when defining a prototype you will probably most of the time choose the first form. This form is more compact and natural. However, if you need to add getters and setters later — because you did not write the prototype or particular object — then the second form is the only possible form. The second form probably best represents the dynamic nature of JavaScript — but it can make the code hard to read and understand.</p> + +<h2 id="Deleting_properties">Deleting properties</h2> + +<p>You can remove a non-inherited property by using the <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code> operator. The following code shows how to remove a property.</p> + +<pre class="brush: js">// Creates a new object, myobj, with two properties, a and b. +var myobj = new Object; +myobj.a = 5; +myobj.b = 12; + +// Removes the a property, leaving myobj with only the b property. +delete myobj.a; +console.log ('a' in myobj); // yields "false" +</pre> + +<p>You can also use <code>delete</code> to delete a global variable if the <code>var</code> keyword was not used to declare the variable:</p> + +<pre class="brush: js">g = 17; +delete g; +</pre> + +<h2 id="Comparing_Objects">Comparing Objects</h2> + +<p>In JavaScript objects are a reference type. Two distinct objects are never equal, even if they have the same properties. Only comparing the same object reference with itself yields true.</p> + +<pre class="brush: js">// Two variables, two distinct objects with the same properties +var fruit = {name: 'apple'}; +var fruitbear = {name: 'apple'}; + +fruit == fruitbear; // return false +fruit === fruitbear; // return false</pre> + +<pre class="brush: js">// Two variables, a single object +var fruit = {name: 'apple'}; +var fruitbear = fruit; // assign fruit object reference to fruitbear + +// here fruit and fruitbear are pointing to same object +fruit == fruitbear; // return true +fruit === fruitbear; // return true +</pre> + +<pre class="brush: js">fruit.name = 'grape'; +console.log(fruitbear); // yields { name: "grape" } instead of { name: "apple" } +</pre> + +<p>For more information about comparison operators, see <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Comparison operators</a>.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>To dive deeper, read about the <a href="/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">details of javaScript's objects model</a>.</li> + <li>To learn about ECMAScript 2015 classes (a new way to create objects), read the <a href="/en-US/docs/Web/JavaScript/Reference/Classes">JavaScript classes</a> chapter.</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</p> |