Common Characteristics of Apply, Bind, and Call
In JavaScript, apply, bind, and call are methods that can be challenging for developers to understand. These three methods share several important characteristics: 1. These functions are all part of Function.prototype, making them available to every function instance in JavaScript. 2. Their primary purpose is to alter the execution context of a function. Consider this example: ```
var globalValue = 1;
function displayValue() {
console.log(this.globalValue);
}
var objectA = {globalValue: 2};
displayValue(); // Equivalent to window.displayValue(), with 'this' pointing to the window/global object
Now, if we want to access the value in objectA, we can do the following: ```
objectA.displayValue = displayValue; // Assign the function as a method of objectA
objectA.displayValue(); // Call the method
Alternatively, we can use these methods: ``` displayValue.call(objectA); // Use call to set objectA as the context displayValue.apply(objectA); // Use apply to set objectA as the context var boundDisplayValue = displayValue.bind(objectA); // Bind objectA as context and return a new function boundDisplayValue();
All three methods successfully access the value in objectA. **Note:** When using bind, `displayValue.bind(objectA)` only changes the context and returns a new function (called a bound function) without immediately executing it. You must manually call the new function to execute it. 3. Call, apply, and bind can accept addiitonal parameters after the first one, which are passed as arguments to the function. The first parameter can accept different values: (1) When omitted, or set to null/undefined, the function's 'this' points to the window object. (2) When another function is passed, 'this' points to that function's reference. (3) When primitive types like strings, numbers, or booleans are passed, 'this' points to their corresponding wrapper objects (String, Number, Boolean). (4) When an object is passed, 'this' points to that object. ```
function showContext() {
console.log(this);
}
showContext.call(); // [object Window]
showContext.call(null); // [object Window]
showContext.call(undefined); // [object Window]
showContext.call(1); // [object Number]
showContext.call('1'); // [object String]
showContext.call(true); // [object Boolean]
showContext.call({a: 1}); // [object Object]{a: 1}
showContext.call(function(a) {console.log(a)}); // function (a){console.log(a)}
Differences Between Call and Apply
As mentioned earlier, bind differs from call and apply because it returns a new function with the bound context without immediately executing it, while call and apply execute the function immediately. The following example demonstrates a polyfill for the native bind() method in ES3, highlighting this distinction: ``` function customBind(fn, context) { if (fn.bind) return fn.bind(context); // Use native bind if available else return function() { // Return a new function that executes in the provided context return fn.apply(context, arguments); } }
The difference between call and apply lies in how they handle arguments. Call accepts individual arguments, while apply accepts an array of arguments. Use call when you know the number of arguments in advance, and apply when working with a variable number of arguments. A common use case is applying the arguments object: The arguments object is an internal property of functions: ```
function testArguments() {
console.log(arguments);
console.log(testArguments.arguments);
console.log(this.arguments);
}
var testObj = {arguments: 'custom arguments'};
testArguments();
/*
[object Arguments]{length: 0}
[object Arguments]{length: 0}
undefined
*/
testArguments(1, '1', true);
/*
[object Arguments]{0: 1, 1: "1", 2: true, length: 3}
[object Arguments]{0: 1, 1: "1", 2: true, length: 3}
undefined
*/
testArguments.call(testObj);
/*
[object Arguments]{length: 0}
[object Arguments]{length: 0}
custom arguments
*/
This example demonstrates that arguments is a property of the function object, accessible within the function via arguments[i]. It also shows that 'this' does not point to the function itself. Finally, here's an example calculating the sum of squares: ``` function calculateSumOfSquares() { var args = Array.prototype.slice.apply(arguments); return args.reduce(function(previous, current) { return previous + current * current; }, 0); } calculateSumOfSquares(1, 2, 4, 6, 8); // 121