Segue um extrato de Closure: The Definitive Guide, de Michael Bolin . Pode parecer um pouco demorado, mas está saturado de muita percepção. Do "Apêndice B. Conceitos de JavaScript frequentemente incompreendidos":
O que thisse refere quando uma função é chamada
Ao chamar uma função do formulário foo.bar.baz(), o objeto foo.baré chamado de receptor. Quando a função é chamada, é o receptor que é usado como o valor para this:
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
Se não houver um receptor explícito quando uma função é chamada, o objeto global se torna o receptor. Conforme explicado em "goog.global" na página 47, window é o objeto global quando o JavaScript é executado em um navegador da web. Isso leva a um comportamento surpreendente:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
Mesmo assim, obj.addValuese se freferem à mesma função, eles se comportam de maneira diferente quando chamados, porque o valor do receptor é diferente em cada chamada. Por esse motivo, ao chamar uma função que se refere this, é importante garantir que thiso valor correto seja chamado. Para ser claro, se thisnão fosse referenciado no corpo da função, o comportamento de f(20)e obj.addValues(20)seria o mesmo.
Como as funções são objetos de primeira classe em JavaScript, elas podem ter seus próprios métodos. Todas as funções possuem os métodos call()e apply()que permitem redefinir o receptor (ou seja, o objeto a que thisse refere) ao chamar a função. As assinaturas de método são as seguintes:
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
Observe que a única diferença entre call()e apply()é que call()recebe os parâmetros da função como argumentos individuais, enquanto os apply()recebe como uma única matriz:
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
As seguintes chamadas são equivalentes, como fe obj.addValuesse referem à mesma função:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
No entanto, como call()nem apply()usa o valor de seu próprio receptor para substituir o argumento do receptor quando não for especificado, o seguinte não funcionará:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
O valor de thisnunca pode ser nullou undefinedquando uma função é chamada. Quando nullou undefinedé fornecido como receptor para call()ou apply(), o objeto global é usado como o valor para o receptor. Portanto, o código anterior tem o mesmo efeito colateral indesejável de adicionar uma propriedade nomeada valueao objeto global.
Pode ser útil pensar em uma função como não tendo conhecimento da variável à qual está atribuída. Isso ajuda a reforçar a ideia de que o valor disso será vinculado quando a função for chamada e não quando for definida.
Fim da extração.
aem candidatar-se a matriz de argumentos ecem chamar por colunas de argumentos.