What is the difference between arguments and parameters in javascript? - javascript

I know that a parameter is a variable passed to a function and gives value to the argument in the function, but I'm having trouble understanding:
What is the main difference between "arguments" and "parameters" in javascript?

The parameters are the aliases for the values that will be passed to the function. The arguments are the actual values.
var foo = function( a, b, c ) {}; // a, b, and c are the parameters
foo( 1, 2, 3 ); // 1, 2, and 3 are the arguments

When you define a function, the variables that represent the values that will be passed to it for processing are called parameters. For example, the following function definition has one parameter called $number:
function doubleIt($number) {
return $number *= 2;
}
However, when you use a function, the value you pass to it is called an argument. So, in the following case, $price is passed as the argument to doubleIt():
$price = 50;
$inflated_price = doubleIt($price); // 100

parameters (if any) define the method signature.
Arguments are values passed into a function.
But same difference I guess.
void function(int param1, string param2) //defines the types the function must receive.
function(1, "Hello World") 1 and "Hello World" are passed as arguments. The parameter receives (if you like) the argument.
It is explained well here

13 Function Definition
Syntax
FunctionDeclaration :
function Identifier ( FormalParameterList (opt) ) { FunctionBody }
FunctionExpression :
function Identifieropt ( FormalParameterList (opt) ) { FunctionBody }
FormalParameterList :
Identifier
FormalParameterList , Identifier
FunctionBody :
SourceElements (opt)
Officially they are called parameters, but the actual arguments are given in the same called object. However, both words are interchangeable.

Parameters are properties of a function.
Arguments are properties of a particular call to a function.
In javascript, if you don't give a number of arguments equal to the number of parameters, the extra come across as undefined.
function f(a,b,c) // 3 parameters
f(1) // 1 argument given; inside the function f, a will be 1, and b and c will be undefined

so parameters works just like a place holder for your arguments
when you going to call the function to give it a value you will give the function a value and that value stored in the place of parameter1 and parameter2
function add (parameter1 , parameter2 ) {
return parameter1 + parameter2;
}
add(10 (argument 1), 20 (argument2 ))

Related

How to pass data to function by the name of the parameters?

I am new to JavaSscript. Basically, I do not want to pass my data by the position of those function parameters. This is inconvenient when there are 10 or more parameters.
I want to pass it by the parameter name defined in the function. However, there is a side-effect when I use this statement: my_func(param01=1). In my view, the usage of param01=1 inside the function call, only represents that 1 is passed to the parameter param01 and no effect happens outside the function call.
This is my code:
function my_func(param01) {
console.log('param01 inside my_func: ', param01)
}
param01 = 3
my_func(param01=1)
console.log('param01 outside my_func: ', param01)
// the result is 1 instead of 3.
My question is: What is the right way to pass data to function by the name of the function parameter?
Use destructuring assignment, In this case the function may accept 10 parameters but you don't need to order the parameters because the value inside the function will be retrieved using key name. Also the parameters can be in any order while calling the function.
function my_func({
param01,
param2,
param3
}) {
console.log('param01 inside my_func: ', param01, param3)
}
param01 = 0
my_func({
param01: 1,
param3: 4
})
console.log('param01 outside my_func: ', param01)
If you want 0 on the outside, but 1 on the inside, you are gonna have a bad time.
The zero you pass in is perfectly acceptable. If you want zero to be a no-no... you can use default operator || which evaluates values for truthiness left-to-right and short-circuits.
function my_func(param01) {
param01 = param01 || 1; // internal = 0 || 1 = 1
console.log('param01 inside my_func: ', param01) // >>> 1
}
param01 = 0 // global = 0
my_func(param01) // pass in the global 0, which IS VALID
console.log('param01 outside my_func:', param01) // >>> 0
Alternatively, you can pass in an object.
function my_func(params={}) {
console.log('param01 inside my_func: ', params.param01) // >>> 1
}
param01 = 0 // global = 0
my_func({ param01 : 1 }) // pass in a 1
console.log('param01 outside my_func:', param01) // >>> 0
I think the main problem here is a misunderstanding as to how parameters work in JavaScript. It looks like you come from a language where this statement:
my_func(param01=1)
Would pass a parameter called param0 with the value 1 to the function.
But in JavaScript this is what happens:
param01 is a variable outside of your function and you assign 1 to it
The result of that assignment expression is 1 so 1 is also passed the the function as a parameter
This explains why param01 is also 1 outside of your function.
In JavaScript you don't specify the parameter names when calling your function. So this works just the same:
my_func(1)
If you want to provide more parameters you have multiple options:
You simply separate them with a comma: my_func(1, 2, 3, 4, 5, 6)
Your function declaration must then look like this:
function my_func(param1, param2, param3, param4, param5, param6)
Or you could use the rest parameter syntax:
function my_func(...params)
This way you can pass as many arguments as you like and they will all be in the params array. You can then access them like this: param[0] for the first parameter, param[1] for the second and so on.
You can create an array with your values and pass the array as a parameter:
const parameters = [1, 2, 3, 4, 5 ,6];
my_func(parameters)
Your function declaration must then look like this:
function my_func(params)
As a side note on clean coding: Your function should have as few parameters as possible. If you have a lot of parameters this usually indicates that the function is doing too many things, thence violates the single responsibility pattern and should be split up into smaller functions.
Param name inside function declaring can be random, while the order is important. But you can use default parameter value in js, to set them by default:
function my_func(param01 = 1) {
console.log('param01 inside my_func: ', param01)
}
You need to define every function parameters like what Jenny and brk did in the comments above.
Jenny:
my_func(1, 2, 3, 4, 5, 6);
blk:
my_func({
param01: 1,
param3: 4
})
You cannot pass 10 or more parameters by the parameter name defined in the function if you don't teach the computer what the 10 or more parameters are.
Please clarify if I misunderstood your question.

How can this function work with a missing parameter

How can callback function work with one parameter when it requires 2 (selector and data) to go? Why doesn't it throw an error?
let links = document.querySelectorAll("a");
links.forEach(function(link){
link.addEventListener("click",function(e){
e.preventDefault();
ajax("get",e.target.href,render)
})
})
function ajax(url,metodo,callback){
let xhr = new XMLHttpRequest
xhr.open(metodo,url)
xhr.addEventListener("load",function(){
if(xhr.status==200){
callback(xhr.response)
}
})
xhr.send()
}
function render(selector,data){
document.querySelector(selector).innerHTML = data
}
In javascript, it is not necessary to call with same number of parameters as defined in function definition. If we do not define a default parameter value in function definition, then parameter becomes type of undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
Default function parameters allow formal parameters to be initialized
with default values if no value or undefined is passed.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Starting with ECMAScript 2015, there are two new kinds of parameters:
default parameters and rest parameters.
Default parameters: In JavaScript, parameters of functions default to
undefined. However, in some situations it might be useful to set a
different default value. This is where default parameters can help.
In the past, the general strategy for setting defaults was to test
parameter values in the body of the function and assign a value if
they are undefined. If in the following example, no value is provided
for b in the call, its value would be undefined when evaluating a*b
and the call to multiply would have returned NaN. However, this is
caught with the second line in this example:
function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1;
return a * b;
}
multiply(5); // 5
With default parameters, the check in the function body is no longer necessary. Now, you can simply put 1 as the default
value for b in the function head:
function multiply(a, b = 1) {
return a * b;
}
multiply(5); // 5
For more details, see default parameters in the reference.
Rest parameters: The rest parameter syntax allows us to represent an
indefinite number of arguments as an array. In the example, we use the
rest parameters to collect arguments from the second one to the end.
We then multiply them by the first one.
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
Argument Object:
Using the arguments object, you can call a function with more
arguments than it is formally declared to accept. This is often useful
if you don't know in advance how many arguments will be passed to the
function. You can use arguments.length to determine the number of
arguments actually passed to the function, and then access each
argument using the arguments object.
For example, consider a function that concatenates several strings.
The only formal argument for the function is a string that specifies
the characters that separate the items to concatenate. The function is
defined as follows:
function myConcat(separator) {
var result = ''; // initialize list
var i;
// iterate through arguments
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
You can pass any number of arguments to this function, and it
concatenates each argument into a string "list":
// returns "red, orange, blue, "
myConcat(', ', 'red', 'orange', 'blue');
// returns "elephant; giraffe; lion; cheetah; "
myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
// returns "sage. basil. oregano. pepper. parsley. "
myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
To make it throw error, if same number of argument is not passed in function, typescript can be used.

Return function with &&?

I am confused about this snippet from command pattern tutorial,
What does it mean by
return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
Also I can understand if it is carManager.execute( "buyVehicle"), then carManager["buyVehicle"] can invoke the function, but what about carManager[buyVehicle", "Ford Escort", "453543"]?
(function(){
var carManager = {
// request information
requestInfo: function( model, id ){
return "The information for " + model + " with ID " + id + " is foobar";
},
// purchase the car
buyVehicle: function( model, id ){
return "You have successfully purchased Item " + id + ", a " + model;
},
// arrange a viewing
arrangeViewing: function( model, id ){
return "You have successfully booked a viewing of " + model + " ( " + id + " ) ";
}
};
})();
carManager.execute = function ( name ) {
return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
};
carManager.execute( "buyVehicle", "Ford Escort", "453543" );
return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
if the function carManager[name] exists in the carManager then execute the function.
carManager[name].apply( carManager, [].slice.call(arguments, 1) );
.apply() is used to invoke a certain function on someother or the same object. it takes the object as the first param and the arguments as the second param. you can provide any object as the first param as long as the function doent cause any change to the object's existing properties. for eg this works the same.
carManager.execute = function ( name ) {
return carManager[name] && carManager[name].apply( {}, [].slice.call(arguments, 1) );
};
code:
[].slice.call(arguments, 1);
.call() does pretty mush the same function as apply(). its taking the slice function of the Array object and invoking it on to some other object, this time on the arguments (object) array. slice returns a part of an array. in this case its just avoiding the first element in the arguments array. ie its making the array without the first element
carManager.execute( "buyVehicle", "Ford Escort", "453543" );
it calls the invoke function. the first argument provides the key of the function. the second and the third arguments provide actual data that has to be passed into the method present in the carManager object. and thats the very reason why the arguments array was sliced.
Simplifying the example:
return f && f();
The way the && operator works in JavaScript is by producing its left operand if its left operand is falsy and its right operand otherwise. It also short-circuits, meaning that if the left operand is falsy, the right operand isn’t evaluated at all. Here, it has the effect of calling f if f is truthy (e.g. a function) and returning its return value, or returning f if f is falsy (e.g. undefined).
In other words, it’s a short way of writing:
return f ? f() : f;
with the actual meaning of:
if (f) {
return f();
}
and when carManager is an object with function properties, that in turn means calling the method named name only if it exists and passing on its return value.
Also I can understand if it is carManager.execute( "buyVehicle"), then carManager["buyVehicle"] can invoke the function, but what about carManager[buyVehicle", "Ford Escort", "453543"]?
This question is a bit hard to interpret but
carManager.execute("buyVehicle", "Ford Escort", "453543")
probably answers it.
It's a guard against the possibility that carManager[name] is a falsy* value (most likely not filled in at all). The code is assuming the property is either missing entirely or has a falsy value, or has a function in it.
If carManager[name] is falsy, it returns that falsy value.
If carManager[name] is not falsy (truthy), the code assumes it's a function and calls it (via apply) and returns whatever it returns.
* "falsy" = false if coerced to boolean. The falsy values are 0, NaN, "", null, undefined, and of course, false. All other values are truthy.
Question 1
When you do:
return carManager[name] && carManager[name].func();
You are saying: check if carManager[name] is untruthy. If it is, return false. Otherwise, execute the func() and return its result.
Question 2
The arguments object can be used to get all the arguments passed to a function, even if they aren't present in the function declaration.
function foo(baz) {
console.log(arguments[0]); // outputs baz: "me"
// same of: console.log(baz);
console.log(arguments[1]); // outputs "you"
console.log(arguments[2]); // outputs "them"
}
foo('me', 'you', 'them'); // call the function, pass 3 arguments

skip function arguments javascript

For example I have this function
function example(a=1,b=1,c=1,d=1,f=1) {
return (a*b*c*d*f)
}
So I have simple function with parameter which have default value.
And now when I call the function if I want to multiply a with f. I need to do that this way:
example(3,1,1,1,5)
Why I can't simply write first and last argument? Is that possible, something like:
example(3[1],5[5])
where numbers [1] and [5] determine the index of argument?
Why I can't simply write first and last argument...
Because that isn't how function calls are defined in the JavaScript specification. That's the only reason.
I would suggest passing an object whenever you are not sure about the number of argument you are going to pass to a function.
If I were in your place, I would have written it as follows in ES5 and earlier:
function example(params) {
var DEFAULT = 1
var a = params.hasOwnProperty('a') ? params.a : DEFAULT;
var b = params.hasOwnProperty('b') ? params.b : DEFAULT;
var c = params.hasOwnProperty('c') ? params.c : DEFAULT;
var d = params.hasOwnProperty('d') ? params.d : DEFAULT;
var e = params.hasOwnProperty('e') ? params.e : DEFAULT;
return (a * b * c * d * e);
}
console.log(example({a: 3, b: 5}));
In ES2015 and above (you're using default arguments, so I assume you're happy with ES2015 features), you can do the above more cleanly using a combination of default arguments and destructuring:
// This snippet requires that your browser support ES2015's default arguments and destructuring
function example({a=1,b=1,c=1,d=1,f=1}={}) {
// Note -------^-------------------^^^^
return (a*b*c*d*f);
}
console.log(example({a:3,f:5}));
There, we define that the actual argument will be an object, rather than discrete arguments, but we receive that object's properties as discrete arguments. We define that each property in the object has a default, and that the object iself is also optional (the ={} at the end). (You can leave off the ={} if you don't want to make example() a valid call.)

What is the difference between call and apply?

What is the difference between using Function.prototype.apply() and Function.prototype.call() to invoke a function?
var func = function() {
alert('hello!');
};
func.apply(); vs func.call();
Are there performance differences between the two aforementioned methods? When is it best to use call over apply and vice versa?
The difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly. A useful mnemonic is "A for array and C for comma."
See MDN's documentation on apply and call.
Pseudo syntax:
theFunction.apply(valueForThis, arrayOfArgs)
theFunction.call(valueForThis, arg1, arg2, ...)
There is also, as of ES6, the possibility to spread the array for use with the call function, you can see the compatibilities here.
Sample code:
function theFunction(name, profession) {
console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
K. Scott Allen has a nice writeup on the matter.
Basically, they differ on how they handle function arguments.
The apply() method is identical to call(), except apply() requires an array as the second parameter. The array represents the arguments for the target method."
So:
// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
To answer the part about when to use each function, use apply if you don't know the number of arguments you will be passing, or if they are already in an array or array-like object (like the arguments object to forward your own arguments. Use call otherwise, since there's no need to wrap the arguments in an array.
f.call(thisObject, a, b, c); // Fixed number of arguments
f.apply(thisObject, arguments); // Forward this function's arguments
var args = [];
while (...) {
args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments
When I'm not passing any arguments (like your example), I prefer call since I'm calling the function. apply would imply you are applying the function to the (non-existent) arguments.
There shouldn't be any performance differences, except maybe if you use apply and wrap the arguments in an array (e.g. f.apply(thisObject, [a, b, c]) instead of f.call(thisObject, a, b, c)). I haven't tested it, so there could be differences, but it would be very browser specific. It's likely that call is faster if you don't already have the arguments in an array and apply is faster if you do.
Here's a good mnemonic. Apply uses Arrays and Always takes one or two Arguments. When you use Call you have to Count the number of arguments.
While this is an old topic, I just wanted to point out that .call is slightly faster than .apply. I can't tell you exactly why.
See jsPerf, http://jsperf.com/test-call-vs-apply/3
[UPDATE!]
Douglas Crockford mentions briefly the difference between the two, which may help explain the performance difference... http://youtu.be/ya4UHuXNygM?t=15m52s
Apply takes an array of arguments, while Call takes zero or more individual parameters! Ah hah!
.apply(this, [...])
.call(this, param1, param2, param3, param4...)
Follows an extract from Closure: The Definitive Guide by Michael Bolin. It might look a bit lengthy, but it's saturated with a lot of insight. From "Appendix B. Frequently Misunderstood JavaScript Concepts":
What this Refers to When a Function is Called
When calling a function of the form foo.bar.baz(), the object foo.bar is referred to as the receiver. When the function is called, it is the receiver that is used as the value for 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);
If there is no explicit receiver when a function is called, then the global object becomes the receiver. As explained in "goog.global" on page 47, window is the global object when JavaScript is executed in a web browser. This leads to some surprising behavior:
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
Even though obj.addValues and f refer to the same function, they behave differently when called because the value of the receiver is different in each call. For this reason, when calling a function that refers to this, it is important to ensure that this will have the correct value when it is called. To be clear, if this were not referenced in the function body, then the behavior of f(20) and obj.addValues(20) would be the same.
Because functions are first-class objects in JavaScript, they can have their own methods. All functions have the methods call() and apply() which make it possible to redefine the receiver (i.e., the object that this refers to) when calling the function. The method signatures are as follows:
/**
* #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;
Note that the only difference between call() and apply() is that call() receives the function parameters as individual arguments, whereas apply() receives them as a single array:
// 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]);
The following calls are equivalent, as f and obj.addValues refer to the same function:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
However, since neither call() nor apply() uses the value of its own receiver to substitute for the receiver argument when it is unspecified, the following will not work:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
The value of this can never be null or undefined when a function is called. When null or undefined is supplied as the receiver to call() or apply(), the global object is used as the value for receiver instead. Therefore, the previous code has the same undesirable side effect of adding a property named value to the global object.
It may be helpful to think of a function as having no knowledge of the variable to which it is assigned. This helps reinforce the idea that the value of this will be bound when the function is called rather than when it is defined.
End of extract.
It is useful at times for one object to borrow the function of another object, meaning that the borrowing object simply executes the lent function as if it were its own.
A small code example:
var friend = {
car: false,
lendCar: function ( canLend ){
this.car = canLend;
}
};
var me = {
car: false,
gotCar: function(){
return this.car === true;
}
};
console.log(me.gotCar()); // false
friend.lendCar.call(me, true);
console.log(me.gotCar()); // true
friend.lendCar.apply(me, [false]);
console.log(me.gotCar()); // false
These methods are very useful for giving objects temporary functionality.
Another example with Call, Apply and Bind.
The difference between Call and Apply is evident, but Bind works like this:
Bind returns an instance of a function that can be executed
First Parameter is 'this'
Second parameter is a Comma separated list of arguments (like Call)
}
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(a,b) {
return this.name + " " + a + " " + b;
}
var reader = new Person('John Smith');
reader.getName = function() {
// Apply and Call executes the function and returns value
// Also notice the different ways of extracting 'getName' prototype
var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
console.log("Apply: " + baseName);
var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy");
console.log("Call: " + baseName);
// Bind returns function which can be invoked
var baseName = Person.prototype.getName.bind(this, "is a", "boy");
console.log("Bind: " + baseName());
}
reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/
I'd like to show an example, where the 'valueForThis' argument is used:
Array.prototype.push = function(element) {
/*
Native code*, that uses 'this'
this.put(element);
*/
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9]
**details: http://es5.github.io/#x15.4.4.7*
Call() takes comma-separated arguments, ex:
.call(scope, arg1, arg2, arg3)
and apply() takes an array of arguments, ex:
.apply(scope, [arg1, arg2, arg3])
here are few more usage examples:
http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/
From the MDN docs on Function.prototype.apply() :
The apply() method calls a function with a given this value and
arguments provided as an array (or an array-like object).
Syntax
fun.apply(thisArg, [argsArray])
From the MDN docs on Function.prototype.call() :
The call() method calls a function with a given this value and arguments provided individually.
Syntax
fun.call(thisArg[, arg1[, arg2[, ...]]])
From Function.apply and Function.call in JavaScript :
The apply() method is identical to call(), except apply() requires an
array as the second parameter. The array represents the arguments for
the target method.
Code example :
var doSomething = function() {
var arr = [];
for(i in arguments) {
if(typeof this[arguments[i]] !== 'undefined') {
arr.push(this[arguments[i]]);
}
}
return arr;
}
var output = function(position, obj) {
document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}
output(1, doSomething(
'one',
'two',
'two',
'one'
));
output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
'one',
'two',
'two',
'one'
]));
output(3, doSomething.call({one : 'Steven', two : 'Jane'},
'one',
'two',
'two',
'one'
));
See also this Fiddle.
Here's a small-ish post, I wrote on this:
http://sizeableidea.com/call-versus-apply-javascript/
var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };
function execute(arg1, arg2){
console.log(this.which, arg1, arg2);
}
//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope
//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope
//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"
Fundamental difference is that call() accepts an argument list, while apply() accepts a single array of arguments.
The difference is that call() takes the function arguments separately, and apply() takes the function arguments in an array.
Summary:
Both call() and apply() are methods which are located on Function.prototype. Therefore they are available on every function object via the prototype chain. Both call() and apply() can execute a function with a specified value of the this.
The main difference between call() and apply() is the way you have to pass in arguments into it. In both call() and apply() you pass as a first argument the object you want to be the value as this. The other arguments differ in the following way:
With call() you have to put in the arguments normally (starting from the second argument)
With apply() you have to pass in array of arguments.
Example:
let obj = {
val1: 5,
val2: 10
}
const summation = function (val3, val4) {
return this.val1 + this.val2 + val3 + val4;
}
console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array
console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually
Why would I need to use these functions?
The this value can be tricky sometimes in javascript. The value of this determined when a function is executed not when a function is defined. If our function is dependend on a right this binding we can use call() and apply() to enforce this behaviour. For example:
var name = 'unwantedGlobalName';
const obj = {
name: 'Willem',
sayName () { console.log(this.name);}
}
let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable
copiedMethod();
// this is now window, unwantedGlobalName gets logged
copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
We can differentiate call and apply methods as below
CALL : A function with argument provide individually.
If you know the arguments to be passed or there are no argument to pass you can use call.
APPLY : Call a function with argument provided as an array. You can use apply if you don't know how many argument are going to pass to the function.
There is a advantage of using apply over call, we don't need to change the number of argument only we can change a array that is passed.
There is not big difference in performance. But we can say call is bit faster as compare to apply because an array need to evaluate in apply method.
The main difference is, using call, we can change the scope and pass arguments as normal, but apply lets you call it using arguments as an Array (pass them as an array). But in terms of what they to do in your code, they are pretty similar.
While the syntax of this function is almost identical to that of
apply(), the fundamental difference is that call() accepts an argument
list, while apply() accepts a single array of arguments.
So as you see, there is not a big difference, but still, there are cases we prefer using call() or apply(). For example, look at the code below, which finding the smallest and largest number in an array from MDN, using the apply method:
// min/max number in an array
var numbers = [5, 6, 2, 3, 7];
// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers);
// This about equal to Math.max(numbers[0], ...)
// or Math.max(5, 6, ...)
var min = Math.min.apply(null, numbers)
So the main difference is just the way we passing the arguments:
Call:
function.call(thisArg, arg1, arg2, ...);
Apply:
function.apply(thisArg, [argsArray]);
Difference between these to methods are, how you want to pass the parameters.
“A for array and C for comma” is a handy mnemonic.
Call and apply both are used to force the this value when a function is executed. The only difference is that call takes n+1 arguments where 1 is this and 'n' arguments. apply takes only two arguments, one is this the other is argument array.
The advantage I see in apply over call is that we can easily delegate a function call to other function without much effort;
function sayHello() {
console.log(this, arguments);
}
function hello() {
sayHello.apply(this, arguments);
}
var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');
Observe how easily we delegated hello to sayHello using apply, but with call this is very difficult to achieve.
Even though call and apply achive the same thing, I think there is atleast one place where you cannot use call but can only use apply. That is when you want to support inheritance and want to call the constructor.
Here is a function allows you to create classes which also supports creating classes by extending other classes.
function makeClass( properties ) {
var ctor = properties['constructor'] || function(){}
var Super = properties['extends'];
var Class = function () {
// Here 'call' cannot work, only 'apply' can!!!
if(Super)
Super.apply(this,arguments);
ctor.apply(this,arguments);
}
if(Super){
Class.prototype = Object.create( Super.prototype );
Class.prototype.constructor = Class;
}
Object.keys(properties).forEach( function(prop) {
if(prop!=='constructor' && prop!=='extends')
Class.prototype[prop] = properties[prop];
});
return Class;
}
//Usage
var Car = makeClass({
constructor: function(name){
this.name=name;
},
yourName: function() {
return this.name;
}
});
//We have a Car class now
var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat
var SuperCar = makeClass({
constructor: function(ignore,power){
this.power=power;
},
extends:Car,
yourPower: function() {
return this.power;
}
});
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6
Let me add a little detail to this.
these two calls are almost equivalent:
func.call(context, ...args); // pass an array as list with spread operator
func.apply(context, args); // is same as using apply
There’s only a minor difference:
The spread operator ... allows passing iterable args as the list to call.
The apply accepts only array-like args.
So, these calls complement each other. Where we expect an iterable, call works, where we expect an array-like, apply works.
And for objects that are both iterable and array-like, like a real array, we technically could use any of them, but apply will probably be faster because most JavaScript engines internally optimize it better.
I just want to add a simple example to a well explained post by flatline, which makes it easy to understand for beginners.
func.call(context, args1, args2 ); // pass arguments as "," separated value
func.apply(context, [args1, args2]); // pass arguments as "Array"
we also use "Call" and "Apply" method for changing reference as defined in code below
let Emp1 = {
name: 'X',
getEmpDetail: function(age, department) {
console.log(`Name: ${this.name} Age: ${age} Department: ${department}`)
}
}
Emp1.getEmpDetail(23, 'Delivery')
// 1st approach of changing "this"
let Emp2 = {
name: 'Y',
getEmpDetail: Emp1.getEmpDetail
}
Emp2.getEmpDetail(55, 'Finance')
// 2nd approach of changing "this" using "Call" and "Apply"
let Emp3 = {
name: 'Emp3_Object',
}
Emp1.getEmpDetail.call(Emp3, 30, 'Admin')
// here we have change the ref from **Emp1 to Emp3** object
// now this will print "Name = Emp3_Object" because it is pointing to Emp3 object
Emp1.getEmpDetail.apply(Emp3, [30, 'Admin'])
The call() method calls a function with a given this value and a second parameter which are arguments separated by comma.
object.someMethod.call( someObject, arguments )
The apply() method is the same as call except the fact that the second argument it takes is an array of arguments .
object.someMethod.apply( someObject, arrayOfarguments )
var car = {
name: "Reno",
country: "France",
showBuyer: function(firstName, lastName) {
console.log(`${firstName} ${lastName} just bought a ${this.name} from ${this.country}`);
}
}
const firstName = "Bryan";
const lastName = "Smith";
car.showBuyer(firstName, lastName); // Bryan just bought a Reno from France
const obj = { name: "Maserati", country: "Italy" };
car.showBuyer.call(obj, firstName, lastName); // Bryan Smith just bought a Maserati from Italy
car.showBuyer.apply(obj, [firstName, lastName]); // Bryan Smith just bought a Maserati from Italy

Categories

Resources