Criação de um array
Alguém usa o construtor new Array()
? Eu particularmente não uso, mas quando vi isso, achei legal deixar registrado pois era algo que não sabia e vai que no dia a dia encontramos algum projeto com isso.
Se criarmos um array através do new Array()
passando argumentos entre os parênteses, temos um array com esses valores que foram passados. Algo assim:
var megaSena = new Array(20, 29, 32, 45, 55, 58); |
Seria o mesmo caso fizéssemos isso:
var megaSena = [20, 29, 32, 45, 55, 58]; |
E se passarmos apenas um valor como argumento? Teríamos um array com apenas um item, certo? Mahomenos… Aí que vem a pegadinha do JavaScript malandro. Se criarmos usando a sintaxe literal, realmente temos um array com apenas um item:
var megaSena = [20]; | |
console.log(megaSena.length); // 1 | |
console.log(megaSena[0]); // 20 |
Agora se criarmos usando new Array()
o que acontece é que esse único valor passado como argumento vira o comprimento do array e não um item dele.
var megaSena = new Array(20); | |
console.log(megaSena.length); // 20 | |
console.log(megaSena[0]); // undefined |
Funções imediatas e parâmetros
Já ouvimos bastante a respeito de funções imediatas, correto? Recapitulando rapidamente, ela permite que uma função seja executada assim que seja definida. Isso é bom principalmente pelo fato de fornecer um escopo temporário para a mágica que você vai fazer, sem a necessidade de poluir seu escopo global.
(function() { | |
// some magic | |
}()); |
Uma coisa bacana é que podemos passar argumentos para as funções imediatas. Podemos então ter algo assim:
(function(name, hobby) { | |
console.log('Hi, my name is ' + name + ' and I like ' + hobby ); | |
}('Fabeni', 'to travel')); | |
// "Hi, my name is Fabeni and I like to travel" |
Como observado pelo Mauricio Soares, uma grande vantagem de passar parâmetros para uma função imediata (IIFE), é que esse valor é passado como uma cópia, e não como uma referência… Isto significa que se alterarmos o valor desse parâmetro dentro da IIFE, esse valor não vai persistir fora dela… por exemplo:
var myVar = true; | |
(function(myVar) { | |
console.log(myVar); // true | |
myVar = false; | |
console.log(myVar); // false | |
}(myVar)); | |
console.log(myVar); // true |
Isso é bom para criarmos cópias de variaveis globais, e garantirmos que se alguem sobreescrever essa variável, isso não vai influenciar o módulo que criamos. Esse comportamento também é conhecido como Closure.
ProTip: É uma excelente prática passarmos o jQuery, window por exemplo,como parâmetros para IIFE’s.
call
e apply
sem medo
Esses dois caras são bem semelhantes. Ambos permitem invocar uma função em um outro contexto (que vai ser o primeiro parâmetro que você vai passar pra eles) e com os argumentos que passarmos (que serão o segundo parâmetro que passarmos). Então, call
e apply
permitem que:
- 1º parâmetro => possamos dizer em qual escopo uma determinada função deve ser executada;
- 2º parâmetro => consigamos definir os argumentos que serão passados para a função.
O que muda entre call
e apply
é a forma de como passar o segundo parâmetro:
call
=> uma lista de itens (a partir do 2º parâmetro);apply
=> um array de elementos.
Para de falar Fabeni, mostra alguma coisa aí!
var mister = { | |
name: 'Val Valentino', | |
nickname: 'Mister M' | |
}; | |
var hello = function(name, nickname) { | |
return 'My name is ' + (name || this.name) + ' but you can also call me ' + (nickname || this.nickname); | |
}; | |
hello.call(mister); | |
// "My name is Val Valentino but you can also call me Mister M" | |
hello.call(null, 'Raphael Fabeni', 'Fabeni'); | |
// "My name is Raphael Fabeni but you can also call me Fabeni" | |
hello.apply(null, ['Raphael Fabeni', 'Fabeni']); | |
// "My name is Raphael Fabeni but you can also call me Fabeni" |
O que temos acima é mais ou menos o seguinte:
- um objeto simples chamado
mister
; - uma função
hello
que retorna umastring
de acordo com os parâmetros passados; - as chamadas das funções usando o formato padrão e usando
call
eapply
.
Um outro exemplo que talvez possa ajudar: vamos imaginar que possamos ter uma função simples que vai iterar sobre os argumentos dessa função (o objeto arguments
). Poderíamos pensar em algo assim:
function something() { | |
var likeArray = arguments; | |
likeArray.forEach(function() {}); | |
return likeArray; | |
} | |
something('a', 'b'); |
Aí que vive o problema: vamos ter um erro se tentarmos algo assim.
TypeError: likeArray.forEach is not a function
Isso acontece pois o nosso brother arguments
é um objeto e não um array. Pra podermos conseguir usar o forEach
, precisamos converter arguments
em um array e conseguimos isso utilizando o método slice
. No entanto, ele é um método que pertence ao prototype
de Array
. Daí que vem a pergunta: como fazemos então pra executar a função/método em um outro contexto (executar slice
no contexto do objeto arguments
)? A resposta meu caro amigo: call
ou apply
.
function something() { | |
var likeArray = Array.prototype.slice.call(arguments); | |
likeArray.forEach(function() {}); | |
return likeArray; | |
} |
No exemplo acima, alteramos a linha relacionada à variável likeArray
, aplicando o método slice
no contexto de arguments
através do call
.
Referências => Learning JavaScript
Deixo aqui meu muito obrigado ao Mauricio Soares, ao Weslley Araujo e ao Frederick Silva pela revisão e contribuição no texto.