URL: https://www.progressiverobot.com/understanding-default-parameters-in-javascript-pt/

*O autor selecionou a COVID-19 Relief Fund​​​​​ para receber uma doação como parte do programa Write for DOnations.*

Introdução

No ECMAScript 2015, os _parâmetros predefinidos de funções_ introduzidos na linguagem JavaScript. Eles permitem que os desenvolvedores inicializem uma função com valores predefinidos, caso os argumentos não sejam fornecidos à chamada da função. Inicializar parâmetros de função desta maneira tornará a leitura delas mais fácil e menos propensa a erros. Além disso, isso providencia um comportamento padrão para elas Isso ajudará você a evitar erros decorrentes da passagem de argumentos undefined (não definidos) e desestruturação de objetos que não existem.

Neste artigo, você irá revisar a diferença entre parâmetros e argumentos, aprender como usar os parâmetros predefinidos em funções, ver maneiras alternativas para dar suporte aos parâmetros predefinidos, além de aprender quais tipos de valores e expressões podem ser usados como parâmetros predefinidos. Você também verá exemplos que demonstram como os parâmetros predefinidos funcionam em JavaScript.

Argumentos e parâmetros

metros predefinidos illustration for: Argumentos e parâmetros

Antes de explicar os parâmetros predefinidos de funções, é importante saber o que esses parâmetros podem usar como predefinição. Por isso, vamos primeiro analisar a diferença entre *argumentos* e *parâmetros* em uma função. Se quiser aprender mais sobre essa distinção, verifique nosso artigo anterior da série JavaScript, Como definir funções em JavaScript.

No bloco de código seguinte, você criará uma função que retorna o cubo de um número determinado, definido como x:

				
					
// Define a function to cube a number

function cube(x) {

  return x * x * x

}

				
			

A variável x neste exemplo é um _parâmetro_ — uma variável com nome passada para uma função. Um parâmetro deve estar sempre contido em uma variável e nunca deve possuir um valor direto.

Agora, dê uma olhada neste próximo bloco de código, que chama a função cube (cubo) que você acabou de criar:

				
					
// Invoke cube function

cube(10)

				
			

Isso dará o seguinte resultado:

				
					
[secondary_label Output]

1000

				
			

Neste caso, 10 é um _argumento_: um valor passado para uma função quando ela é invocada. Muitas vezes, o valor também estará contido em uma variável, como neste próximo exemplo:

				
					
// Assign a number to a variable

const number = 10



// Invoke cube function

cube(number)

				
			

Isso gerará o mesmo resultado:

				
					
[secondary_label Output]

1000

				
			

Se você não passar um argumento para uma função que espere um, a função utilizará implicitamente undefined como o valor:

				
					
// Invoke the cube function without passing an argument

cube()

				
			

Isso retornará:

				
					
[secondary_label Output]

NaN

				
			

Neste caso, cube() está tentando calcular o valor de undefined * undefined * undefined, que resulta em NaN, ou "not a number" (não é um número). Para obter mais informações sobre isso, consulte a seção de números do Entendendo tipos de dados em JavaScript.

Às vezes, esse comportamento automático pode causar problemas. Em alguns casos, você pode querer que o parâmetro tenha um valor, mesmo se nenhum argumento tiver sido passado para a função. São nesse casos em que a funcionalidade de _parâmetros predefinidos_ vem a calhar, um tópico que será abordado na próxima seção.

Sintaxe dos parâmetros predefinidos

Com a adição dos parâmetros predefinidos no ES2015, você pode agora atribuir um valor predefinido para qualquer parâmetro. A função utilizará esse valor, ao invés de undefined quando chamada sem um argumento. Esta seção mostrará primeiro como fazer isso manualmente. Em seguida, irá guiar você na definição de parâmetros predefinidos.

Sem os parâmetros predefinidos, você teria que verificar explicitamente se há valores undefined para definir os padrões, como mostrado neste exemplo:

				
					
// Check for undefined manually

function cube(x) {

  if (typeof x === 'undefined') {

    x = 5

  }



  return x * x * x

}



cube()

				
			

Ele utiliza uma instrução condicional para verificar se o valor foi provisionado automaticamente como undefined. Em seguida, define o valor de x como 5. Isso resultará no seguinte:

				
					
[secondary_label Output]

125

				
			

Em contrapartida, usar os parâmetros predefinidos atinge o mesmo objetivo com um código muito menor. Defina um valor predefinido para o parâmetro em cube, atribuindo-lhe o operador de atribuição de igualdade (=), como destacado aqui:

				
					
// Define a cube function with a default value

function cube(<^>x = 5<^>) {

  return x * x * x

}

				
			

Agora, quando a função cube for invocada sem um argumento, ela atribuirá 5 a x e retornará o cálculo ao invés de NaN:

				
					
// Invoke cube function without an argument

cube()

				
			
				
					
[secondary_label Output]

125

				
			

Ela ainda funcionará como previsto quando um argumento for passado, ignorando o valor predefinido:

				
					
// Invoke cube function with an argument

cube(2)

				
			
				
					
[secondary_label Output]

8

				
			

No entanto, um ponto negativo importante a se considerar é que o valor predefinido do parâmetro também substituirá um undefined explicitamente passado como um argumento para uma função, como demonstrado aqui:

				
					
// Invoke cube function with undefined

cube(undefined)

				
			

Isso resultará no cálculo com x igual a 5:

				
					
[secondary_label Output]

125

				
			

Neste caso, os valores predefinidos dos parâmetros foram calculados, e um valor undefined explícito não os substituíram.

Agora que você tem uma ideia da sintaxe básica dos parâmetros predefinidos, a próxima seção mostrará como os parâmetros predefinidos funcionam com diferentes tipos de dados.

Tipos de dados dos parâmetros predefinidos

Qualquer valor primitivo ou objeto pode ser usado como um valor predefinido do parâmetro. Nesta seção, você verá como essa flexibilidade aumenta as maneiras como os parâmetros predefinidos podem ser usados.

Primeiro, defina os parâmetros usando um número, string, booleano, objeto, matriz e valor nulo como um valor predefinido. Este exemplo utilizará a sintaxe arrow function:

				
					
// Create functions with a default value for each data type

const defaultNumber = (number = 42) => console.log(number)

const defaultString = (string = 'Shark') => console.log(string)

const defaultBoolean = (boolean = true) => console.log(boolean)

const defaultObject = (object = { id: 7 }) => console.log(object)

const defaultArray = (array = [1, 2, 3]) => console.log(array)

const defaultNull = (nullValue = null) => console.log(nullValue)

				
			

Quando essas funções forem invocadas sem parâmetros, elas usarão todos os valores predefinidos:

				
					
// Invoke each function

defaultNumber()

defaultString()

defaultBoolean()

defaultObject()

defaultArray()

defaultNull()

				
			
				
					
[secondary_label Output]

42

"Shark"

true

{id: 7}

(3) [1, 2, 3]

null

				
			

Note que qualquer objeto criado em um parâmetro predefinido será criado sempre que a função for chamada. Um dos casos de uso comum para os parâmetros predefinidos é o uso deste comportamento para obter valores de um objeto. Se você tentar desestruturar ou acessar um valor de um objeto que não existe, ele emitirá um erro. No entanto, se o parâmetro predefinido for um objeto vazio, ele simplesmente retornará valores undefined, ao invés de emitir um erro:

				
					
// Define a settings function with a default object

function settings(options = {}) {

  const { theme, debug } = options



  // Do something with settings

}

				
			

Isso evitará erros causados pela desestruturação de objetos que não existem.

Agora que você viu como os parâmetros predefinidos operam com diferentes tipos de dados, a próxima seção explicará como vários parâmetros predefinidos podem funcionar em conjunto.

Usando multiplos parâmetros predefinidos

Use quantos parâmetros predefinidos quiser em uma função. Esta seção mostrará como fazê-lo e como usar isso para manipular o DOM em um exemplo real.

Primeiro, declare uma função sum() com múltiplos parâmetros predefinidos:

				
					
// Define a function to add two values

function sum(a = 1, b = 2) {

  return a + b

}



sum()

				
			

Isso resultará no cálculo predefinido a seguir:

				
					
[secondary_label Output]

3

				
			

Além disso, o valor usado em um parâmetro pode ser usado em qualquer parâmetro predefinido subsequente, da esquerda para a direita. Por exemplo, esta função createUser cria um objeto de usuário userObj como sendo o terceiro parâmetro e tudo o que a função faz é retornar userObj com os dois primeiros parâmetros:

				
					
// Define a function to create a user object using parameters

function createUser(name, rank, userObj = { name, rank }) {

  return userObj

}



// Create user

const user = createUser('Jean-Luc Picard', 'Captain')

				
			

Se você chamar o user aqui, você receberá o seguinte:

				
					
[secondary_label Output]

{name: "Jean-Luc Picard", rank: "Captain"}

				
			

Geralmente, é recomendável colocar todos os parâmetros predefinidos no final de uma lista de parâmetros, para que você possa deixar de fora valores opcionais facilmente. Se você usar um parâmetro predefinido primeiro, você terá que passar explicitamente undefined para usar o valor predefinido.

Aqui está um exemplo com o parâmetro predefinido no início da lista:

				
					
// Define a function with a default parameter at the start of the list

function defaultFirst(a = 1, b) {

  return a + b

}

				
			

Ao chamar esta função, você teria que chamar o defaultFirst() com dois argumentos:

				
					
defaultFirst(undefined, 2)

				
			

Isso resultaria no seguinte:

				
					
[secondary_label Output]

3

				
			

Aqui está um exemplo com o parâmetro predefinido no final da lista:

				
					
// Define a function with a default parameter at the end of the list

function defaultLast(a, b = 1) {

  return a + b

}



defaultLast(2)

				
			

Isso resultaria no mesmo valor:

				
					
[secondary_label Output]

3

				
			

Ambas as funções têm o mesmo resultado, mas aquela com o valor predefinido por último resulta em uma chamada de função muito mais limpa.

Para um exemplo real, aqui está uma função que criará um elemento DOM e adicionará um rótulo de texto e classes, caso existam.

				
					
// Define function to create an element

function createNewElement(tag, text, classNames = []) {

  const el = document.createElement(tag)

  el.textContent = text



  classNames.forEach(className => {

    el.classList.add(className)

  })



  return el

}

				
			

Chame a função com algumas classes em uma matriz:

				
					
const greeting = createNewElement('p', 'Hello!', ['greeting', 'active'])

				
			

Chamar greeting resultará no valor a seguir:

				
					
[secondary_label Output]

<p class="greeting active">Hello!</p>

				
			

No entanto, se você deixar a matriz classNames fora da chamada da função, ela ainda funcionará.

				
					
const greeting2 = createNewElement('p', 'Hello!')

				
			

greeting2 tem agora o valor a seguir:

				
					
[secondary_label Output]

<p>Hello!</p>

				
			

Neste exemplo, o forEach()) pode ser usado em uma matriz vazia sem problemas. Se aquela matriz vazia não fosse definida no parâmetro predefinido, você receberia o erro a seguir:

				
					
[secondary_label Output]

VM2673:5 Uncaught TypeError: Cannot read property 'forEach' of undefined

    at createNewElement (<anonymous>:5:14)

    at <anonymous>:12:18

				
			

Agora que você viu como multiplos parâmetros predefinidos podem interagir, continue para a próxima seção para ver como as chamadas de função funcionam como parâmetros predefinidos.

Chamadas de função como parâmetros predefinidos

Além dos primitivos e objetos, o resultado de chamar uma função pode ser usado como parâmetro predefinido.

Neste bloco de código, você criará uma função para retornar um número aleatório e, em seguida, usará o resultado como o valor predefinido de parâmetro em uma função cube:

				
					
// Define a function to return a random number from 1 to 10

function getRandomNumber() {

  return Math.floor(Math.random() * 10)

}



// Use the random number function as a default parameter for the cube function

function cube(x = getRandomNumber()) {

  return x * x * x

}

				
			

Agora, invocar a função cube sem um parâmetro vai gerar resultados potencialmente diferentes sempre que você chamá-la:

				
					
// Invoke cube function twice for two potentially different results

cube()

cube()

				
			

Os resultados destas chamadas de função variará:

				
					
[secondary_label Output]

<^>512<^>

<^>64<^>

				
			

Você pode até mesmo usar métodos integrados, como aqueles presentes no objeto Math, e usar o valor retornado em uma chamada de função como um parâmetro em outra função.

No exemplo a seguir, um número aleatório é atribuído a x, que é usado como parâmetro na função cube que você criou. Em seguida, o parâmetro y calculará a raiz cúbica do número e verificará para ver se x e y são iguais:

				
					
// Assign a random number to x

// Assign the cube root of the result of the cube function and x to y

function doesXEqualY(x = getRandomNumber(), y = Math.cbrt(cube(x))) {

  return x === y

}



doesXEqualY()

				
			

Isso resultará no seguinte:

				
					
[secondary_label Output]

true

				
			

Um parâmetro predefinido pode até ser uma definição de função, como visto neste exemplo, que define um parâmetro como a função inner (interna) e retorna a chamada de função de parameter:

				
					
// Define a function with a default parameter that is an anonymous function

function outer(

  parameter = function inner() {

    return 100

  }

) {

  return parameter()

}



// Invoke outer function

outer()

				
			
				
					
[secondary_label Output]

100

				
			

Essa função inner será criada a partir do zero toda vez que a função outer (externa) for invocada.

Conclusão

Neste artigo, você aprendeu o que são os parâmetros predefinidos de função e como usá-los. Agora, você pode usar os parâmetros predefinidos para ajudar a manter suas funções limpas e fáceis de ler. Você também pode atribuir objetos vazios e matrizes a parâmetros logo no início. Isso reduz a complexidade e o número de linhas de código ao lidar com situações como a recuperação de valores de um objeto ou a execução de um loop em uma matriz.

Se quiser aprender mais sobre o JavaScript, confira a página inicial de nossa série sobre Como programar em JavaScript, ou pesquise nossa série sobre Como programar em Node.js para obter artigos sobre o desenvolvimento de back-end.