From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../global_objects/array/reduce/index.html | 513 +++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 files/pt-br/web/javascript/reference/global_objects/array/reduce/index.html (limited to 'files/pt-br/web/javascript/reference/global_objects/array/reduce/index.html') diff --git a/files/pt-br/web/javascript/reference/global_objects/array/reduce/index.html b/files/pt-br/web/javascript/reference/global_objects/array/reduce/index.html new file mode 100644 index 0000000000..0268b64c00 --- /dev/null +++ b/files/pt-br/web/javascript/reference/global_objects/array/reduce/index.html @@ -0,0 +1,513 @@ +--- +title: Array.prototype.reduce() +slug: Web/JavaScript/Reference/Global_Objects/Array/Reduce +tags: + - Array + - JavaScript + - Métodos + - Prototipo + - Referencia + - reduce() +translation_of: Web/JavaScript/Reference/Global_Objects/Array/Reduce +--- +
{{JSRef}}
+ +

O método reduce() executa uma função reducer (fornecida por você) para cada elemento do array, resultando num único valor de retorno.

+ +
{{EmbedInteractiveExample("pages/js/array-reduce.html")}}
+ + + +

A função reducer recebe quatro parâmetros:

+ +
    +
  1. Acumulador (acc)
  2. +
  3. Valor Atual (cur)
  4. +
  5. Index Atual (idx)
  6. +
  7. Array original (src)
  8. +
+ +

O valor de retorno da sua função reducer é atribuída ao acumulador. O acumulador, com seu valor atualizado, é repassado para cada iteração subsequente pelo array, que por fim, se tornará o valor resultante, único, final.

+ +

Sintaxe

+ +
array.reduce(callback( acumulador, valorAtual[, index[, array]] )[, valorInicial]))
+ +

Parâmetros

+ +
+
callback
+
Função que é executada em cada valor no array (exceto no primeiro, se nenhum valorInicial for passado); recebe quatro argumentos:
+
+ +

acumulador

+ +

Opcional. O índice do elemento atual que está sendo processado no array. Começa a partir do index 0 se um valorInicial for fornecido. Do contrário, começa do index 1.

+ +
+
valorInicial
+
Opcional. Valor a ser usado como o primeiro argumento da primeira chamada da função callback. Se nenhum valorInicial é fornecido, o primeiro elemento do array será usado como o valor inicial do acumulador e o valorAtual não será lido. Chamar reduce() em uma array vazia sem valor inicial retornará um erro.
+
+ +

Valor retornado

+ +

O valor que resulta da redução.

+ +

Descrição

+ +

O método reduce() executa a função de callback uma vez para cada elemento presente no array, excluindo furos (valores indefinidos), recebendo quatro argumentos:

+ +
    +
  1. acumulador - valor inicial (ou o valor do callback anterior),
  2. +
  3. valorAtual - o valor do elemento atual
  4. +
  5. index - o índice atual e
  6. +
  7. array - o array onde a iteração está ocorrendo.
  8. +
+ +

A primeira vez que o callback é chamado, o acumulador e o valorAtual podem ter um de dois valores possíveisSe o valorInicial tiver sido fornecido na chamada à função reduce(), então o acumulador será igual ao valorInicial e o valorAtual será igual ao primeiro valor no array. Caso nenhum valorInicial seja fornecido, acumulador será igual ao primeiro valor no array, e valorAtual será igual ao segundo.

+ +
+

Nota: Se o valorInicial não tiver sido passado como argumento, então reduce() executará o callback da função começando a partir do índice 1 (index 1), pulando o primeiro índice (index 0). Se o valorInicial for passado como argumento, a função irá começar no index 0.

+
+ +

Se a array estiver vazia e o valorInicial não tiver sido informado, uma exceção do tipo {{jsxref("Global_Objects/TypeError", "TypeError")}} será lançada.

+ +

Se a array possuir somente um elemento (independente da posição) e o valorInicial não tiver sido fornecido, ou se valorInicial for fornecido, mas a array estiver vazia, o valor será retornado sem que a função de callback seja chamada.

+ +

É mais seguro provir um valorInicial, porque existem até quatro possíveis saídas sem o valorInicial, como mostrado no exemplo:

+ +
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
+var maxCallback2 = ( max, cur ) => Math.max( max, cur );
+
+// reduce() sem valores iniciais
+[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42
+[ { x: 22 }            ].reduce( maxCallback ); // { x: 22 }
+[                      ].reduce( maxCallback ); // TypeError
+
+// map/reduce; melhor solução, funciona para vetores vazios e tambem para vetores grandes
+[ { x: 22 }, { x: 42 } ].map( el => el.x )
+                        .reduce( maxCallback2, -Infinity );
+ +

Como funciona o reduce()

+ +

Suponha que o seguinte uso de reduce() tenha ocorrido:

+ +
[0, 1, 2, 3, 4].reduce(function(acumulador, valorAtual, index, array) {
+  return acumulador + valorAtual;
+});
+// 10
+ +

O callback será invocado quatro vezes, com os argumentos e valores em cada chamada  sendo:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
acumuladorvalorAtualindexarrayvalor de retorno
primeira chamada011[0, 1, 2, 3, 4]1
segunda chamada122[0, 1, 2, 3, 4]3
terceira chamada333[0, 1, 2, 3, 4]6
quarta chamada644[0, 1, 2, 3, 4]10
+ +

O valor retornado pelo reduce será o da última chamada à callback (10).

+ +

Você também pode usar uma {{jsxref("Functions/Arrow_functions", "Arrow Function","",1)}} em vez de uma função completa. O código abaixo produz a mesma saída que o código do bloco acima:

+ +
[0, 1, 2, 3, 4].reduce( (accum, curr) => accum + curr );
+ +

Se você informar um valorInicial como o segundo argumento de reduce, o resultado será:

+ +
[0, 1, 2, 3, 4].reduce(function(acumulador, valorAtual, indice, array) {
+  return acumulador + valorAtual;
+}, 10);
+
+// 20
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
callbackacumuladorvalorAtualindexarrayvalor de retorno
primeira chamada1000[0, 1, 2, 3, 4]10
segunda chamada1011[0, 1, 2, 3, 4]11
terceira chamada1122[0, 1, 2, 3, 4]13
quarta chamada1333[0, 1, 2, 3, 4]16
quinta chamada1644[0, 1, 2, 3, 4]20
+ +

O retorno da última chamada 20,é retornado como resultado da função reduce().

+ +

Exemplos

+ +

Soma todos os valores de uma array

+ +
let total = [0, 1, 2, 3].reduce(function(acumulador, valorAtual) {
+   return acumulador + valorAtual;
+ }, 0)
+// retorna 6
+ +

outra alternativa é usar uma arrow function:

+ +
var total = [ 0, 1, 2, 3 ].reduce(
+  ( acumulador, valorAtual ) => acumulador + valorAtual,
+  0
+);
+ +

Soma de valores de um objeto de um array

+ +

Para resumir os valores contidos em um array, você deve fornecer um valorInicial, para que cada item passe por sua função.

+ +
var valorInicial = 0;
+var soma = [{x: 1}, {x: 2}, {x: 3}].reduce(function (acumulador, valorAtual) {
+    return acumulador + valorAtual.x;
+}, valorInicial)
+
+console.log(soma) // retorna 6
+ +

Utilizando uma arrow function:

+ +
var valorInicial = 0;
+var soma = [{x: 1}, {x: 2}, {x: 3}].reduce(
+    (acumulador , valorAtual) => acumulador + valorAtual.x
+    , valorInicial
+);
+
+console.log(soma) // retorna 6
+
+ +

Redução de um array de arrays

+ +
let reduzido = [[0, 1], [2, 3], [4, 5]].reduce(
+  function(acumulador, valorAtual) {
+    return acumulador.concat(valorAtual)
+  },
+  []
+)
+// reduzido é [0, 1, 2, 3, 4, 5]
+ +

Utilizando uma arrow function:

+ +
let reduzido = [[0, 1], [2, 3], [4, 5]].reduce(
+  ( acumulador, valorAtual ) => acumulador.concat(valorAtual),
+  []
+);
+ +

Contando valores iguais em um objeto

+ +
let nomes = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
+
+let quantidadeNomes = nomes.reduce(function (todosNomes, nome) {
+  if (nome in todosNomes) {
+    todosNomes[nome]++;
+  }
+  else {
+    todosNomes[nome] = 1;
+  }
+  return todosNomes;
+}, {});
+// quantidade de nomes:
+// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
+
+ +

Agrupando objetos por uma propriedade

+ +
let pessoas = [
+  { nome: 'Alice', idade: 21 },
+  { nome: 'Max', idade: 20 },
+  { nome: 'Jane', idade: 20 }
+];
+
+function agruparPor(objetoArray, propriedade) {
+  return objetoArray.reduce(function (acc, obj) {
+    let key = obj[propriedade];
+    if (!acc[key]) {
+      acc[key] = [];
+    }
+    acc[key].push(obj);
+    return acc;
+  }, {});
+}
+
+let grupodePessoas = agruparPor(pessoas, 'idade');
+// grupodePessoas é:
+// {
+//   20: [
+//     { nome: 'Max', idade: 20 },
+//     { nome: 'Jane', idade: 20 }
+//   ],
+//   21: [{ nome: 'Alice', idade: 21 }]
+// }
+ +

Juntando arrays contidos num array de objetos usando o operador spread e o valorInicial

+ +
// friends - um array de objetos
+// onde o campo "books" é a lista de livros favoritos
+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 - lista que contém todos os livros de friends +
+// lista adicional contida em valorInicial
+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'
+// ]
+ +

Removendo itens duplicados num array

+ +
+

Nota: Se você estiver usando um ambiente compatível com {{jsxref("Set")}} and {{jsxref("Array.from()")}}, você pode usar let orderedArray = Array.from(new Set(myArray)) para obter um array em que os itens duplicados tenham sido removidos.

+
+ +
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]
+
+ +

Substituindo .filter().map() por .reduce()

+ +

Usar {{jsxref("Array.filter()")}} seguido por {{jsxref("Array.map()")}} faz com que o array seja percorrido duas vezes. Você pode obter o mesmo resultado percorrendo o array apenas uma vez com {{jsxref("Array.reduce()")}}, o que é, portanto, mais eficiente. (Se você gosta de for loops, você pode usar filter e map percorrendo o array apenas uma vez com {{jsxref("Array.forEach()")}}).

+ +
const numbers = [-5, 6, 2, 0,];
+
+const doubledPositiveNumbers = numbers.reduce((accumulator, currentValue) => {
+  if (currentValue > 0) {
+    const doubled = currentValue * 2;
+    accumulator.push(doubled);
+  }
+  return accumulator;
+}, []);
+
+console.log(doubledPositiveNumbers); // [12, 4]
+ +

Rodando promises em sequência

+ +
/**
+ * Roda promises de um promise array de uma maneira encadeada
+ *
+ * @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
+  });
+ +

Escrever map usando reduce

+ +
if (!Array.prototype.mapUsingReduce) {
+  Array.prototype.mapUsingReduce = function(callback, thisArg) {
+    return this.reduce(function(mappedArray, currentValue, index, array) {
+      mappedArray[index] = callback.call(thisArg, currentValue, index, array)
+      return mappedArray
+    }, [])
+  }
+}
+
+[1, 2, , 3].mapUsingReduce(
+  (currentValue, index, array) => currentValue + index + array.length
+) // [5, 7, , 10]
+ +

Polyfill

+ +

Array.prototype.reduce foi adicionado ao padrão ECMA-262  na quinta edição; e portanto, pode não estar presente em todas as implementações do padrão. Você pode contornar isso inserindo o código a seguir no início de seus scripts, permitindo o uso do reduce() em implementações que não possuem suporte nativo a ele.

+ +
// Etapas de produção para o ECMA-262, Edition 5, 15.4.4.21
+// Referencia: http://es5.github.io/#x15.4.4.21
+if (!Array.prototype.reduce) {
+  Array.prototype.reduce = function(callback /*, valorInicial*/) {
+    'use strict';
+    if (this == null) {
+      throw new TypeError('Array.prototype.reduce chamado é nulo (null) ou indefinido (undefined)');
+    }
+    if (typeof callback !== 'function') {
+      throw new TypeError(callback + ' não é uma função')
+    }
+    var t = Object(this), len = t.length >>> 0, k = 0, value;
+    if (arguments.length == 2) {
+      value = arguments[1];
+    } else {
+      while (k < len && !(k in t)) {
+        k++;
+      }
+      if (k >= len) {
+        throw new TypeError('Reduce possui um array vazio sem um valor inicial');
+      }
+      value = t[k++];
+    }
+    for (; k < len; k++) {
+      if (k in t) {
+        value = callback(value, t[k], k, t);
+      }
+    }
+    return value;
+  };
+}
+
+ +

Especificações

+ + + + + + + + + + + + + + + + + + + +
EspecificaçãoStatusComentário
{{SpecName('ES5.1', '#sec-15.4.4.21', 'Array.prototype.reduce')}}{{Spec2('ES5.1')}} +

Definição inicial. Implemetada no JavaScript 1.8.

+
{{SpecName('ES6', '#sec-array.prototype.reduce', 'Array.prototype.reduce')}}{{Spec2('ES6')}}
+ +

Navegadores compatíveis

+ +

A tabela de compatibilidade encontrada nesta página é gerada a partir de dados estruturados. Se você deseja contribuir com os dados, consulte : https://github.com/mdn/browser-compat-data e envie-nos um "pull request".

+ +
{{Compat("javascript.builtins.Array.reduce")}}
+ +

Leia também

+ + -- cgit v1.2.3-54-g00ecf