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/reference/operators/destructuring_assignment | |
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/reference/operators/destructuring_assignment')
-rw-r--r-- | files/zh-tw/web/javascript/reference/operators/destructuring_assignment/index.html | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/operators/destructuring_assignment/index.html b/files/zh-tw/web/javascript/reference/operators/destructuring_assignment/index.html new file mode 100644 index 0000000000..0cae43e2b5 --- /dev/null +++ b/files/zh-tw/web/javascript/reference/operators/destructuring_assignment/index.html @@ -0,0 +1,423 @@ +--- +title: 解構賦值 +slug: Web/JavaScript/Reference/Operators/Destructuring_assignment +tags: + - Destructuring + - Destructuring_assignment + - ECMAScript 2015 + - ES6 + - JavaScript + - Language feature + - Operator + - 解構 +translation_of: Web/JavaScript/Reference/Operators/Destructuring_assignment +--- +<div>{{jsSidebar("Operators")}}</div> + +<p><strong>解構賦值</strong> (Destructuring assignment) 語法是一種 JavaScript 運算式,可以把陣列或物件中的資料解開擷取成為獨立變數。</p> + +<div>{{EmbedInteractiveExample("pages/js/expressions-destructuringassignment.html", "taller")}}</div> + + + +<h2 id="語法">語法</h2> + +<pre class="brush:js">let a, b, rest; +[a, b] = [10, 20]; +console.log(a); // 10 +console.log(b); // 20 + +[a, b, ...rest] = [10, 20, 30, 40, 50]; +console.log(a); // 10 +console.log(b); // 20 +console.log(rest); // [30, 40, 50] + +({ a, b } = { a: 10, b: 20 }); +console.log(a); // 10 +console.log(b); // 20 + + +// Stage 4(finished) proposal +({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}); +console.log(a); // 10 +console.log(b); // 20 +console.log(rest); // {c: 30, d: 40} +</pre> + +<h2 id="描述">描述</h2> + +<p>物件與陣列運算式提供了簡單的方式,建立特定的資料組。</p> + +<pre class="brush: js">const x = [1, 2, 3, 4, 5];</pre> + +<p>解構賦值使用類似語法;不過在指定敘述式的左側,要宣告從來源變數接收解開值之變數。</p> + +<pre class="brush: js">const x = [1, 2, 3, 4, 5]; +const [y, z] = x; +console.log(y); // 1 +console.log(z); // 2 +</pre> + +<p>Perl 和 Python 也有類似的語法和功能。</p> + +<h2 id="陣列解構">陣列解構</h2> + +<h3 id="基本變數指定敘述">基本變數指定敘述</h3> + +<pre class="brush: js">const foo = ['one', 'two', 'three']; + +const [red, yellow, green] = foo; +console.log(red); // "one" +console.log(yellow); // "two" +console.log(green); // "three" +</pre> + +<h3 id="宣告指派分開敍述">宣告指派分開敍述</h3> + +<p>變數可以在宣告式後,再透過解構賦值。</p> + +<pre class="brush:js">let a, b; + +[a, b] = [1, 2]; +console.log(a); // 1 +console.log(b); // 2 +</pre> + +<h3 id="預設值">預設值</h3> + +<p>當解構來源陣列對應的元素是 undefined 時,變數可以被設定預設值。</p> + +<pre class="brush: js">let a, b; + +[a=5, b=7] = [1]; +console.log(a); // 1 +console.log(b); // 7 +</pre> + +<h3 id="變數交換">變數交換</h3> + +<p>兩個變數可以透過一個解構指派式交換。</p> + +<p>沒有解構指派式時,這需要一個暫存變數來達成(或者像某些低階語言的 <a class="external" href="https://en.wikipedia.org/wiki/XOR_swap_algorithm">XOR-swap trick</a>)。</p> + +<pre class="brush:js">let a = 1; +let b = 3; + +[a, b] = [b, a]; +console.log(a); // 3 +console.log(b); // 1 + +const arr = [1,2,3]; +[arr[2], arr[1]] = [arr[1], arr[2]]; +console.log(arr); // [1,3,2] + +</pre> + +<h3 id="解析自函式回傳的陣列">解析自函式回傳的陣列</h3> + +<p>一直以來函式都可以回傳陣列,而解構指派式可以讓回傳的值更加簡潔。</p> + +<p>在這個例子, <code>f()</code> 回傳 <code>[1, 2]</code> ,接著透過一個解構指派式解析。</p> + +<pre class="brush:js">function f() { + return [1, 2]; +} + +let a, b; +[a, b] = f(); +console.log(a); // 1 +console.log(b); // 2 +</pre> + +<h3 id="忽略某些回傳值">忽略某些回傳值</h3> + +<p>你可以忽略某些回傳值:</p> + +<pre class="brush:js">function f() { + return [1, 2, 3]; +} + +const [a, , b] = f(); +console.log(a); // 1 +console.log(b); // 3 +</pre> + +<p>當然你也可以忽略全部回傳值:</p> + +<pre class="brush:js">[,,] = f(); +</pre> + +<h3 id="把矩陣剩餘部分解構到一個變數">把矩陣剩餘部分解構到一個變數</h3> + +<p>解構一個陣列時,你可以透過其餘元素(rest pattern)將來源剩下之元素指派到一個變數:</p> + +<pre class="brush: js">const [a, ...b] = [1, 2, 3]; +console.log(a); // 1 +console.log(b); // [2, 3]</pre> + +<p>要注意的是,當左邊函式裡使用其餘解構,同時使用結尾逗號,這樣會拋出例外 {{jsxref("SyntaxError")}} :</p> + +<pre class="brush: js example-bad">const [a, ...b,] = [1, 2, 3]; + +// SyntaxError 語法錯誤: 其餘元素不可以跟隨結尾逗號 +// 需要把其餘運算子放在最後的元素 +</pre> + +<h3 id="從正則運算式的比對結果取值">從正則運算式的比對結果取值</h3> + +<p>當正則運算式的方法 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec">exec()</a></code> 比對到一個值,其回傳陣列中的第一個值是相符的完整字串,後績的則是比對到正則運算式每組括號內的部分。當你沒需要利用第一個完整比對結果時,解構指派式讓你更簡單的取出後績元素。</p> + +<pre class="brush:js">function parseProtocol(url) { + const parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url); + if (!parsedURL) { + return false; + } + console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"] + + const [, protocol, fullhost, fullpath] = parsedURL; + return protocol; +} + +console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "https" +</pre> + +<h2 id="物件解構">物件解構</h2> + +<h3 id="基本指派式">基本指派式</h3> + +<pre class="brush: js">const o = {p: 42, q: true}; +const {p, q} = o; + +console.log(p); // 42 +console.log(q); // true +</pre> + +<h3 id="無宣告指派">無宣告指派</h3> + +<p>變數可以在宣告式後,再透過解構進行指派。</p> + +<pre class="brush:js">let a, b; + +({a, b} = {a:1, b:2});</pre> + +<div class="note"> +<p><strong>注意</strong>:當針對物件進行解構,而該句式沒有進行宣告時,指派式外必須加上括號 <code>( ... )</code> 。</p> + +<p><code>{a, b} = {a: 1, b: 2}</code> 不是有效的獨立語法,因為左邊的 <code>{a, b}</code> 被視為程式碼區塊而非物件。</p> + +<p>然而,<code>({a, b} = {a: 1, b: 2})</code> 是有效的,如同 <code>const {a, b} = {a: 1, b: 2}</code></p> + +<p><code>( ... )</code> 表達式前句需要以分號結束,否則可能把上一句視為函式隨即執行。</p> +</div> + +<h3 id="指派到新的變數名稱">指派到新的變數名稱</h3> + +<p>物件中的屬性可以解構並擷取到名稱跟該屬性不一樣的變數。</p> + +<pre class="brush: js">const o = {p: 42, q: true}; +const {p: foo, q: bar} = o; + +console.log(foo); // 42 +console.log(bar); // true</pre> + +<p>舉例來說, <code>const {p: foo} = o</code> 把物件 <code>o</code> 裡名為 <code>p</code> 的屬性解出並指派到一個名為 <code>foo</code> 的本地變數。</p> + +<h3 id="預設值_2">預設值</h3> + +<p>當解構物件中對應的值是 <code>undefined</code> 時,變數可以設定預設值。</p> + +<pre class="brush: js">const {a = 10, b = 5} = {a: 3}; + +console.log(a); // 3 +console.log(b); // 5</pre> + +<h3 id="指定新的變數名稱及預設值">指定新的變數名稱及預設值</h3> + +<p>屬性 1) 可以從物件中被解開,且被指定一個不同名稱的變數及 2) 同時指定一個預設值,在解開的值為 <code>undefined</code> 時使用。</p> + +<pre class="brush: js">const {a:aa = 10, b:bb = 5} = {a: 3}; + +console.log(aa); // 3 +console.log(bb); // 5 +</pre> + +<h3 id="從作為函式參數的物件中提出某屬性的值">從作為函式參數的物件中提出某屬性的值</h3> + +<pre class="brush:js">const user = { + id: 42, + displayName: 'jdoe', + fullName: { + firstName: 'John', + lastName: 'Doe' + } +}; + +function userId({id}) { + return id; +} + +function whois({displayName, fullName: {firstName: name}}) { + return `${displayName} is ${name}`; +} + +console.log(userId(user)); // 42 +console.log(whois(user)); // "jdoe is John"</pre> + +<p>這樣從 user 物件中提出了 <code>id</code>, <code>displayName</code> 和 <code>firstName</code> 並且印出。</p> + +<h3 id="設定函式參數的預設值">設定函式參數的預設值</h3> + +<pre class="brush: js">function drawChart({size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}) { + console.log(size, coords, radius); + // do some chart drawing +} + +drawChart({ + coords: {x: 18, y: 30}, + radius: 30 +});</pre> + +<div class="note"> +<p>在上述函式 <strong><code>drawChart</code></strong> 中,左方之解構式被指派到一個空物件: <code>{size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}</code> 。你也可以略過填寫右方的指派式。不過,當你沒有使用右方指派式時,函式在呼叫時會找出最少一個參數。透過上述形式,你可以直接不使用參數的呼叫 <code><strong>drawChart()</strong></code> 。當你希望在呼叫這個函式時不傳送參數,這個設計會帶來方便。而另一個設計則能讓你確保函式必須傳上一個物件作為參數。</p> +</div> + +<h3 id="巢狀物件或陣列的解構">巢狀物件或陣列的解構</h3> + +<pre class="brush:js">const metadata = { + title: 'Scratchpad', + translations: [ + { + locale: 'de', + localization_tags: [], + last_edit: '2014-04-14T08:43:37', + url: '/de/docs/Tools/Scratchpad', + title: 'JavaScript-Umgebung' + } + ], + url: '/en-US/docs/Tools/Scratchpad' +}; + +let { + title: englishTitle, // rename + translations: [ + { + title: localeTitle, // rename + }, + ], +} = metadata; + +console.log(englishTitle); // "Scratchpad" +console.log(localeTitle); // "JavaScript-Umgebung"</pre> + +<h3 id="循環取出的解構">循環取出的解構</h3> + +<pre class="brush: js">const people = [ + { + name: 'Mike Smith', + family: { + mother: 'Jane Smith', + father: 'Harry Smith', + sister: 'Samantha Smith' + }, + age: 35 + }, + { + name: 'Tom Jones', + family: { + mother: 'Norah Jones', + father: 'Richard Jones', + brother: 'Howard Jones' + }, + age: 25 + } +]; + +for (const {name: n, family: {father: f}} of people) { + console.log('Name: ' + n + ', Father: ' + f); +} + +// "Name: Mike Smith, Father: Harry Smith" +// "Name: Tom Jones, Father: Richard Jones" +</pre> + +<h3 id="以物件演算屬性名稱解構">以物件演算屬性名稱解構</h3> + +<p>物件演算屬性名稱(像是在 <a href="/zh-TW/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names">object literals</a>)可以在解構指派式使用。</p> + +<pre class="brush: js">let key = 'z'; +let {[key]: foo} = {z: 'bar'}; + +console.log(foo); // "bar" +</pre> + +<h3 id="在物件解構時使用其餘變數">在物件解構時使用其餘變數</h3> + +<p><a class="external external-icon" href="https://github.com/tc39/proposal-object-rest-spread">ECMAScript 中的其餘/展開屬性</a>在 proposal (stage 4) 新增了在解構式內使用<a href="/zh-TW/docs/Web/JavaScript/Reference/Functions/rest_parameters">其餘 (rest)</a> 語法的定義。其餘屬性可以收集解構式中沒有指定的屬性值。</p> + +<pre class="brush: js">let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40} +a; // 10 +b; // 20 +rest; // { c: 30, d: 40 }</pre> + +<h3 id="不符合_JavaScript_識別字的屬性名稱">不符合 JavaScript 識別字的屬性名稱</h3> + +<p>解構賦值可以透過另一個符合 JavaScript <a href="/zh-TW/docs/Glossary/Identifier">識別字</a>的變數名稱來解出不符合識別字的屬性。</p> + +<pre class="brush: js">const foo = { 'fizz-buzz': true }; +const { 'fizz-buzz': fizzBuzz } = foo; + +console.log(fizzBuzz); // "true" +</pre> + +<h3 id="混合使用矩陣及物件解構">混合使用矩陣及物件解構</h3> + +<p>矩陣及物件解構可以混合進行。與例來說,你只需要使用下列 <code>props</code> 矩陣中第三個元素之物件中的 <code>name</code> 屬性,你可以如下面的例子進行解構:</p> + +<pre class="brush: js">const props = [ + { id: 1, name: 'Fizz'}, + { id: 2, name: 'Buzz'}, + { id: 3, name: 'FizzBuzz'} +]; + +const [,, { name }] = props; + +console.log(name); // "FizzBuzz" +</pre> + +<h3 id="物件解構時的原型鏈追溯">物件解構時的原型鏈追溯</h3> + +<p>在進行物件解構時,如果一個屬性不在其當下存取,將會透過原型鏈 (prototype chain) 來進行追溯。</p> + +<pre>let obj = {self: '123'}; +obj.__proto__.prot = '456'; +const {self, prot} = obj; +// self "123" +// prot "456"(Access to the prototype chain)</pre> + +<h2 id="規範">規範</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">規範</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-destructuring-assignment', 'Destructuring assignment')}}</td> + </tr> + </tbody> +</table> + +<h2 id="瀏覽器相容性">瀏覽器相容性</h2> + +<div> + + +<p>{{Compat("javascript.operators.destructuring")}}</p> +</div> + +<h2 id="參見">參見</h2> + +<ul> + <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Operators/Assignment_Operators">Assignment operators</a></li> + <li><a href="https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/">"ES6 in Depth: Destructuring" on hacks.mozilla.org</a></li> +</ul> |