Front End

21 nov, 2012

Fundamentos de JavaScript: Funções

Publicidade

Em JavaScript, as funções são uma parte integrante do desenvolvimento. É nelas que está toda a nossa incrível funcionalidade (daí o nome “função”) e as executaremos sempre que acharmos que vale a pena. Com funções, nós podemos tornar o código não-linear, mais organizado e mais fácil de entender. Nós também podemos fazer algumas coisas malucas com programação funcional.

Definindo uma função

Antes de podermos usar uma função, é preciso criar uma, não é? Bem, tecnicamente, existem muitas funções built-in que podemos começar a usar imediatamente, mas não é certo ficar sem uma ordem. Então, vamos definir uma função.

Há duas sintaxes que podem ser usadas para declarar funções: a declaração de função regular e atribuindo uma função de expressão a uma variável/propriedade. Saca só:

// regular declaration
function foo() {
// body of the function. Do Stuff Here!
};

// assign expression to variable
var foo = function() {
// body of the function. Do Stuff Here!
};

Para a maior parte, elas alcançam os mesmos resultados. A maior diferença diz respeito à variável elevação de uma forma bastante impressionante. Dustin Diaz explica essa diferença de declarações de função. Eu prefiro ficar com a segunda sintaxe, independentemente do que Diaz diz, porque eu gosto de ter o nome da função bem onde você pode ver e porque eu acho que é errado tratar as funções de forma diferente de todo mundo. Além disso, essa é a sintaxe que você precisa usar se você deseja atribuir uma função como uma propriedade de um objeto. Falando neles…

Funções são objetos

O quê? Não, elas não são! Eles são funções! Bem, sim, mas as funções também são objetos. As funções podem ter propriedades próprias atribuídas a elas e, de fato, elas automaticamente têm algumas assim que são criadas. Vamos falar sobre algumas delas um pouco mais tarde. Por agora, basta verificar este JavaScript perfeitamente válido.

var foo = function() {
// body of the function. Do Stuff Here!
};

foo.awesomeProperty = "AWESOME";

Infelizmente, porém, não podemos atribuir um lindo objeto literal para uma função porque isso iria substituir a função em si. É possível, no entanto, ainda atribuir um objeto literal para uma das propriedades da função. Mas tenho certeza de que você poderia ter descoberto isso sozinho.

Chamando uma função

Agora que temos algumas funções, vamos usá-las! Você pensou que chamar uma função seria a parte simples, certo? Bem, existem, realmente, várias maneiras para chamar uma função, o que é provavelmente a parte mais difícil de aprender, a não ser que você seja preguiçoso e só use o modo normal (o que é possível, mas pode atrapalhá-lo em código mais avançado).

Normal

Vamos começar com o modo normal de chamar uma função. Tudo o que você precisa é adicionar alguns parênteses após o nome da função e, possivelmente, alguns argumentos dentro desses parênteses.

var foo = function( arg1, arg2, arg3 ) {
// body of the function. Do Stuff Here!
};

foo();
// or
foo(1, 2, 3);

Existe algo que é realmente impressionante sobre as chamadas de função do JavaScript, que eu pensei que fosse um saco no início, quando comecei a usar JavaScript depois que eu vim de um background Java. Você pode chamar uma função com qualquer número de argumentos e não obter um erro! Isso é realmente incrível, porque permite que você crie funções com parâmetros “opcionais” e faça algo completamente diferente, dependendo do número de argumentos enviados. O jQuery faz muito isso com getters e setters. A parte chata é que você pode ter que verificar para se certificar de que as pessoas estão enviando o número certo e os tipos corretos de argumentos. No entanto, se você documentar o seu código suficientemente bem, você pode simplesmente alegar que o problema é deles se eles usarem os argumentos errados, e os erros irão informá-los.

Há outra coisa legal sobre isso. Você não precisa definir os parâmetros na sua declaração de função. Em vez disso, todos os argumentos podem ser acessados via arguments dentro da função. Olha só.

var foo = function() {
console.log(arguments);
};

foo();          // (nothing to output)
// or
foo(1, 2, 3);   // [1,2,3]

arguments é uma estrutura do tipo array. Na realidade, é um tipo especial de objeto que age como um array em muitos casos, mas possui sua própria funcionalidade e muitas vezes não terá a mesma funcionalidade que um array tem. Então, se você quer que ele seja um array, use slice para convertê-lo em um array.

var foo = function() {
var args = Array.prototype.slice.call(arguments);
};

Se você não tem certeza do que está acontecendo exatamente aqui, tudo bem. Você vai descobrir em breve em uma seção abaixo.

Usando new para constructors

Eu já escrevi anteriormente sobre os objetos JavaScript. Falei sobre como você pode escrever uma função e, em seguida, usar new para fazer um novo objeto com ela. Bem, isso é apenas outra maneira de chamar uma função. Eu não vou me preocupar em entrar em detalhes, mas quero mencionar que o prototype é uma propriedade de uma função como falamos anteriormente e que você vai ver naquele artigo.

call e apply

Estas duas funções são as propriedades de cada função. Elas podem ser usadas para chamar uma função com um contexto diferente. O contexto é o que controla o significado da palavra-chave this, e ser capaz de controlar dinamicamente o contexto pode ser útil pra caramba, especialmente em uma situação de retorno de chamada.

var foo = function() {
console.log(this.location);
};
var someObject = {
location: "here"
};

// by default `this` refers to the window, so this will log the current URL
foo();

// here we set the context to `someObject`, so it will log "here"
foo.call(someObject);

Isso pode permitir que você use essencialmente qualquer função como se fosse parte de qualquer objeto, mesmo sendo definida de uma maneira completamente separada. No exemplo acima, só vimos call ser utilizado. Nesse exemplo, usar apply teria rendido o mesmo resultado. A única diferença entre call e apply é a maneira como eles enviam argumentos para a função que estão chamando. Outro exemplo de código pode explicar isso melhor do que apenas palavras, então eu vou te mostrar primeiro.

var foo = function(arg1, arg2) {
console.log(arg1);
console.log(arg2);
};

var bar = function(arg1, arg2) {
foo.call(this, arg1, arg2);
foo.apply(this, [arg1, arg2]);
foo.apply(this, arguments);
};

bar(1, 2);

A função foo apenas registra cada um dos seus dois argumentos. Nada de especial. A função bar, no entanto, chama foo de três maneiras diferentes para demonstrar call e apply. Para ambos call e apply, o primeiro argumento é o contexto, o que no caso deste exemplo realmente não importa, então eu só joguei alguma coisa ali. A diferença entre as duas funções aparece depois do primeiro argumento. Para call, você fornece um número arbitrário de argumentos, cada um dos quais é passado para a função que está sendo chamad como argumentos individuais. Por outro lado, apply pega apenas um argumento a mais, que deve ser um array ou a estrutura do tipo array (tal como arguments, como eu demonstrei no exemplo). Cada elemento do array é então enviado para a função que está sendo chamada como argumentos individuais.

Chamando as funções Parent/Super

Agora que entendemos call e apply, podemos usá-las para algo interessante (além de converter arguments em um array como eu mostrei anteriormente). Nós vamos usá-las para chamar funções Super em classes parents. Dê uma olhada:

// Define a class with a single function
var Foo = function() {
// …
};
Foo.prototype.someFunc = function() {
// …
};

// A second class
var Bar = function() {
// …
};
// Inherits from Foo
Bar.prototype = new Foo();
// Override `someFunc` in the child class
Bar.prototype.someFunc = function() {
// …
// We still want to call the parent `someFunc`, but it needs to be called as if it's part of this object
Foo.prototype.someFunc.apply(this, arguments);
}

Essa é uma maneira muito longa e chata para dizer super(), mas agora vamos ter que lidar com isso. Pelo menos você sabe que você ainda pode fazê-lo em JavaScript. Mas, em ECMAScript.next, isso deve mudar com a introdução de classes. Obviamente, não haverá qualquer tipo de suporte em navegadores mais antigos, então ainda vai demorar um tempo antes que ele possa obter uso mainstream.

Programação funcional

Eu não estou muito familiarizado com programação funcional, mas você pode fazer algumas coisas de maneiras muito estranhas e surpreendentes com uma mentalidade funcional. Se você quiser ver um pedacinho de programação funcional, pode conferir este artigo no DailyJS. Eu não vou me preocupar em entrar nessa coisa porque não sou muito bom nisso, e há recursos muito melhores para ele disponível em toda a web.

Conclusão

Isso engloba tudo o que eu queria falar sobre funções. Não é exatamente um artigo curto, mas isso é só porque as funções JavaScript são muito flexíveis e impressionantes. Espero que todos tenham aprendido algo útil. Deus os abençoe e feliz codificação.

***

Texto original disponível em http://www.joezimjs.com/javascript/javascript-fundamentals-functions/