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/global_objects/array/reduce | |
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/global_objects/array/reduce')
-rw-r--r-- | files/zh-tw/web/javascript/reference/global_objects/array/reduce/index.html | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/global_objects/array/reduce/index.html b/files/zh-tw/web/javascript/reference/global_objects/array/reduce/index.html new file mode 100644 index 0000000000..1f943d8dfa --- /dev/null +++ b/files/zh-tw/web/javascript/reference/global_objects/array/reduce/index.html @@ -0,0 +1,472 @@ +--- +title: Array.prototype.reduce() +slug: Web/JavaScript/Reference/Global_Objects/Array/Reduce +tags: + - Array + - ECMAScript 5 + - JavaScript + - Method + - Prototype + - Reduce + - Reference +translation_of: Web/JavaScript/Reference/Global_Objects/Array/Reduce +--- +<div>{{JSRef}}</div> + +<p><code><strong>reduce()</strong></code> 方法將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。</p> + +<div>{{EmbedInteractiveExample("pages/js/array-reduce.html")}}</div> + +<h2 id="語法">語法</h2> + +<pre class="syntaxbox"><var>arr</var>.reduce(<var>callback[accumulator, currentValue, currentIndex, array], </var><var>initialValue</var>)</pre> + +<h3 id="參數">參數</h3> + +<dl> + <dt><code>callback</code></dt> + <dd>用於處理陣列中每個元素的函式,可傳入四個參數: + <dl> + <dt><code>accumulator</code></dt> + <dd>用來累積回呼函式回傳值的累加器(accumulator)或 <code>initialValue</code>(若有提供的話,詳如下敘)。累加器是上一次呼叫後,所回傳的累加數值。</dd> + <dt><code>currentValue</code></dt> + <dd>原陣列目前所迭代處理中的元素。</dd> + <dt><code>currentIndex</code>{{optional_inline}}</dt> + <dd>原陣列目前所迭代處理中的元素之索引。若有傳入 <code>initialValue</code>,則由索引 0 之元素開始,若無則自索引 1 之元素開始。</dd> + <dt><code>array</code>{{optional_inline}}</dt> + <dd>呼叫 <code>reduce()</code> 方法的陣列。</dd> + </dl> + </dd> + <dt><code>initialValue</code>{{optional_inline}}</dt> + <dd>於第一次呼叫 <code>callback</code> 時要傳入的累加器初始值。若沒有提供初始值,則原陣列的第一個元素將會被當作初始的累加器。假如於一個空陣列呼叫 <code>reduce()</code> 方法且沒有提供累加器初始值,將會發生錯誤。</dd> +</dl> + +<h3 id="回傳值">回傳值</h3> + +<p>簡化後的結果值。</p> + +<h2 id="描述">描述</h2> + +<p><code>reduce()</code> 會對每一個目前迭代到的陣列元素(除了空值以外)執行 <code>callback</code> 函式,回呼函式會接收四個參數:</p> + +<ul> + <li><code>accumulator</code></li> + <li><code>currentValue</code></li> + <li><code>currentIndex</code></li> + <li><code>array</code></li> +</ul> + +<p>當回呼函式第一次被呼叫時,<code>accumulator</code> 與 <code>currentValue</code> 的值可能為兩種不同的狀況:若在呼叫 <code>reduce()</code> 時有提供 <code>initialValue</code>,則 <code>accumulator</code> 將會等於 <code>initialValue</code>,且 <code>currentValue</code> 會等於陣列中的第一個元素值;若沒有提供 <code>initialValue</code>,則 <code>accumulator</code> 會等於陣列的第一個元素值,且 <code>currentValue</code> 將會等於陣列的第二個元素值。</p> + +<div class="note"> +<p><strong>備註:</strong>假如 <code>initialValue</code> 未被提供,<code>reduce()</code> 將會跳過第一個陣列索引,從陣列索引 1 開始執行回呼函式。若有提供 <code>initialValue</code>,則會由陣列索引 0 開始執行。</p> +</div> + +<p>若陣列為空且沒有提供 <code>initialValue</code>,將會拋出 {{jsxref("TypeError")}}。假如陣列只有一個元素(無論其索引位置為何)並且沒有提供 <code>initialValue</code>,或如果提供了 <code>initialValue</code> 但陣列為空,則此唯一的值將會被直接回傳<em>而不會呼叫 <code>callback</code> 函式</em>。</p> + +<p>提供累加器初始值通常較為安全,因為在沒有傳入 <code>initialValue</code> 的情況下會有三種可能的輸出結果,如下列範例:</p> + +<pre class="brush: js">var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x ); +var maxCallback2 = ( max, cur ) => Math.max( max, cur ); + +// reduce() without initialValue +[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42 +[ { x: 22 } ].reduce( maxCallback ); // { x: 22 } +[ ].reduce( maxCallback ); // TypeError + +// map/reduce; better solution, also works for empty or larger arrays +[ { x: 22 }, { x: 42 } ].map( el => el.x ) + .reduce( maxCallback2, -Infinity ); +</pre> + +<h3 id="reduce()_如何運作">reduce() 如何運作</h3> + +<p>假設 <code>reduce()</code> 以下例方式使用:</p> + +<pre class="brush: js">[0, 1, 2, 3, 4].reduce( + function ( +<code> accumulator,</code> + <code>currentValue</code>, + <code>currentIndex</code>, + array + ) { + return <code>accumulator</code> + currentValue; + } +); +</pre> + +<p>所傳入的回呼函式將被呼叫四次,所傳入的參數與回傳值如下所示:</p> + +<table> + <thead> + <tr> + <th scope="col"><code>callback</code></th> + <th scope="col"><code>accumulator</code></th> + <th scope="col"><code>currentValue</code></th> + <th scope="col"><code>currentIndex</code></th> + <th scope="col"><code>array</code></th> + <th scope="col">return value</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">first call</th> + <td><code>0</code></td> + <td><code>1</code></td> + <td><code>1</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>1</code></td> + </tr> + <tr> + <th scope="row">second call</th> + <td><code>1</code></td> + <td><code>2</code></td> + <td><code>2</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>3</code></td> + </tr> + <tr> + <th scope="row">third call</th> + <td><code>3</code></td> + <td><code>3</code></td> + <td><code>3</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>6</code></td> + </tr> + <tr> + <th scope="row">fourth call</th> + <td><code>6</code></td> + <td><code>4</code></td> + <td><code>4</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>10</code></td> + </tr> + </tbody> +</table> + +<p><code>reduce()</code> 的最終回傳值將會是最後一次呼叫回呼函式的回傳值 (<code>10</code>)。</p> + +<p>你也可以傳入一個{{jsxref("Functions/Arrow_functions", "箭頭函式","",1)}}來替代一個完整的函式。下方的程式碼執行的結果將與前述例子相同。</p> + +<pre class="brush: js">[0, 1, 2, 3, 4].reduce( (prev, curr) => prev + curr ); +</pre> + +<p>如果你有提供第二個參數值給 <code>reduce()</code>,執行的結果如下:</p> + +<pre class="brush: js">[0, 1, 2, 3, 4].reduce( + (<code>accumulator</code>, currentValue, currentIndex, array) => { + return <code>accumulator</code> + currentValue; + }, + 10 +); +</pre> + +<table> + <thead> + <tr> + <th scope="col"><code>callback</code></th> + <th scope="col"><code>accumulator</code></th> + <th scope="col"><code>currentValue</code></th> + <th scope="col"><code>currentIndex</code></th> + <th scope="col"><code>array</code></th> + <th scope="col">return value</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">first call</th> + <td><code>10</code></td> + <td><code>0</code></td> + <td><code>0</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>10</code></td> + </tr> + <tr> + <th scope="row">second call</th> + <td><code>10</code></td> + <td><code>1</code></td> + <td><code>1</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>11</code></td> + </tr> + <tr> + <th scope="row">third call</th> + <td><code>11</code></td> + <td><code>2</code></td> + <td><code>2</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>13</code></td> + </tr> + <tr> + <th scope="row">fourth call</th> + <td><code>13</code></td> + <td><code>3</code></td> + <td><code>3</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>16</code></td> + </tr> + <tr> + <th scope="row">fifth call</th> + <td><code>16</code></td> + <td><code>4</code></td> + <td><code>4</code></td> + <td><code>[0, 1, 2, 3, 4]</code></td> + <td><code>20</code></td> + </tr> + </tbody> +</table> + +<p><code>reduce()</code> 執行的結果將會是 <code>20</code>。</p> + +<h2 id="範例">範例</h2> + +<h3 id="加總所有陣例之元素值">加總所有陣例之元素值</h3> + +<pre class="brush: js">var sum = [0, 1, 2, 3].reduce(function (a, b) { + return a + b; +}, 0); +// sum is 6 +</pre> + +<p>另外,也可以寫成箭頭函式:</p> + +<pre class="brush: js">var total = [ 0, 1, 2, 3 ].reduce( + ( acc, cur ) => acc + cur, + 0 +);</pre> + +<h3 id="攤平一個多維陣列">攤平一個多維陣列</h3> + +<pre class="brush: js">var flattened = [[0, 1], [2, 3], [4, 5]].reduce( + function(a, b) { + return a.concat(b); + }, + [] +); +// flattened is [0, 1, 2, 3, 4, 5] +</pre> + +<p>另外,也可以寫成箭頭函式:</p> + +<pre class="brush: js">var flattened = [[0, 1], [2, 3], [4, 5]].reduce( + ( acc, cur ) => acc.concat(cur), + [] +); +</pre> + +<h3 id="計算相同元素數量並以物件鍵值顯示">計算相同元素數量並以物件鍵值顯示</h3> + +<pre class="brush: js">var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; + +var countedNames = names.reduce(function (allNames, name) { + if (name in allNames) { + allNames[name]++; + } + else { + allNames[name] = 1; + } + return allNames; +}, {}); +// countedNames is: +// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } +</pre> + +<h3 id="使用_spread_運算子與給定初始值,結合物件中的陣列元素">使用 spread 運算子與給定初始值,結合物件中的陣列元素</h3> + +<pre class="brush: js">// friends - an array of objects +// where object field "books" - list of favorite books +var friends = [{ + name: 'Anna', + books: ['Bible', 'Harry Potter'], + age: 21 +}, { + name: 'Bob', + books: ['War and peace', 'Romeo and Juliet'], + age: 26 +}, { + name: 'Alice', + books: ['The Lord of the Rings', 'The Shining'], + age: 18 +}]; + +// allbooks - list which will contain all friends' books + +// additional list contained in initialValue +var allbooks = friends.reduce(function(prev, curr) { + return [...prev, ...curr.books]; +}, ['Alphabet']); + +// allbooks = [ +// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace', +// 'Romeo and Juliet', 'The Lord of the Rings', +// 'The Shining' +// ]</pre> + +<p> </p> + +<h3 id="移除陣列中的重複項目">移除陣列中的重複項目</h3> + +<pre class="brush: js">let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]; +let result = arr.sort().reduce((init, current) => { + if (init.length === 0 || init[init.length - 1] !== current) { + init.push(current); + } + return init; +}, []); +console.log(result); //[1,2,3,4,5] +</pre> + +<h3 id="序列執行_Promise">序列執行 Promise</h3> + +<pre class="brush: js">/** + * Runs promises from promise array in chained manner + * + * @param {array} arr - promise arr + * @return {Object} promise object + */ +function runPromiseInSequense(arr) { + return arr.reduce((promiseChain, currentPromise) => { + return promiseChain.then((chainedResult) => { + return currentPromise(chainedResult) + .then((res) => res) + }) + }, Promise.resolve()); +} + +// promise function 1 +function p1() { + return new Promise((resolve, reject) => { + resolve(5); + }); +} + +// promise function 2 +function p2(a) { + return new Promise((resolve, reject) => { + resolve(a * 2); + }); +} + +// promise function 3 +function p3(a) { + return new Promise((resolve, reject) => { + resolve(a * 3); + }); +} + +const promiseArr = [p1, p2, p3]; +runPromiseInSequense(promiseArr) + .then((res) => { + console.log(res); // 30 + }); + +</pre> + +<h2 id="Polyfill">Polyfill</h2> + +<pre class="brush: js">// Production steps of ECMA-262, Edition 5, 15.4.4.21 +// Reference: http://es5.github.io/#x15.4.4.21 +// https://tc39.github.io/ecma262/#sec-array.prototype.reduce +if (!Array.prototype.reduce) { + Object.defineProperty(Array.prototype, 'reduce', { + value: function(callback /*, initialValue*/) { + if (this === null) { + throw new TypeError( 'Array.prototype.reduce ' + + 'called on null or undefined' ); + } + if (typeof callback !== 'function') { + throw new TypeError( callback + + ' is not a function'); + } + + // 1. Let O be ? ToObject(this value). + var o = Object(this); + + // 2. Let len be ? ToLength(? Get(O, "length")). + var len = o.length >>> 0; + + // Steps 3, 4, 5, 6, 7 + var k = 0; + var value; + + if (arguments.length >= 2) { + value = arguments[1]; + } else { + while (k < len && !(k in o)) { + k++; + } + + // 3. If len is 0 and initialValue is not present, + // throw a TypeError exception. + if (k >= len) { + throw new TypeError( 'Reduce of empty array ' + + 'with no initial value' ); + } + value = o[k++]; + } + + // 8. Repeat, while k < len + while (k < len) { + // a. Let Pk be ! ToString(k). + // b. Let kPresent be ? HasProperty(O, Pk). + // c. If kPresent is true, then + // i. Let kValue be ? Get(O, Pk). + // ii. Let accumulator be ? Call( + // callbackfn, undefined, + // « accumulator, kValue, k, O »). + if (k in o) { + value = callback(value, o[k], k, o); + } + + // d. Increase k by 1. + k++; + } + + // 9. Return accumulator. + return value; + } + }); +} +</pre> + +<p>如果還需要支援老舊到不支援 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a></code> 的 JavaScript 引擎,最好不要 polyfill <code>Array.prototype</code> 方法,因為你無法令其不可枚舉(non-enumerable)。</p> + +<h2 id="規範">規範</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">規範</th> + <th scope="col">狀態</th> + <th scope="col">註解</th> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.4.4.21', 'Array.prototype.reduce()')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>Initial definition. Implemented in JavaScript 1.8.</td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-array.prototype.reduce', 'Array.prototype.reduce()')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-array.prototype.reduce', 'Array.prototype.reduce()')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="瀏覽器相容性">瀏覽器相容性</h2> + +<div> + + +<p>{{Compat("javascript.builtins.Array.reduce")}}</p> +</div> + +<h2 id="參見">參見</h2> + +<ul> + <li>{{jsxref("Array.prototype.reduceRight()")}}</li> +</ul> |