context to use call and apply in Javascript? - javascript

Guys can any one explain context to use call and apply methods in Javascript?
Why to use call and apply instead of calling a function directly ?

You use call or apply when you want to pass a different this value to the function. In essence, this means that you want to execute a function as if it were a method of a particular object. The only difference between the two is that call expects parameters separated by commas, while apply expects parameters in an array.
An example from Mozilla's apply page, where constructors are chained:
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.apply(this, arguments);
this.category = 'food';
}
Food.prototype = new Product();
function Toy(name, price) {
Product.apply(this, arguments);
this.category = 'toy';
}
Toy.prototype = new Product();
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
What Product.apply(this, arguments) does is the following: The Product constructor is applied as a function within each of the Food and Toy constructors, and each of these object instances are being passed as this. Thus, each of Food and Toy now have this.name and this.category properties.

Only if you use call or apply you can modify the this context inside the function.
Unlike other languages - in JavaScript this does not refer to the current object - rather to the execution context and can be set by the caller.
If you call a function using the new keyword this will correctly refer to the new object (inside the constructor function)..
But in all other cases - this will refer to the global object unless set explicitly through call

You use .call() when you want to cause a function to execute with a different this value. It sets the this value as specified, sets the arguments as specified and then calls the function. The difference between .call() and just executing the function is the value of the this pointer when the function executes. When you execute the function normally, javascript decides what the this pointer will be (usually the global context window unless the function is called as a method on an object). When you use .call(), you specify exactly what you want this to be set to.
You use .apply() when the arguments you want to pass to a function are in an array. .apply() can also cause a function to execute with a specific this value. .apply() is most often used when you have an indeterminate number of arguments that are coming from some other source. It is often used too pass the arguments from one function call to another by using the special local variable arguments which contains an array of arguments that were passed to your current function.
I find the MDN references pages for .call() and .apply() helpful.

If you have experience with jQuery, you will know that most functions take use of the this object. For example, collection.each(function() { ... });
Inside this function, "this" refers to the iterator object. This is one possible usage.
I personally have used .apply() for implementing a queue of requests - I push an array of arguments into the queue, and when the time comes for executing it, I take an element, and pass it as the arguments for a handler function using .apply(), thus making the code cleaner then if having to pass an array of arguments as a first argument. That's another example.
In general, just keep in mind that those ways to call a function exist, and you may one day find them convenient to use for implementing your program.

If you have experience with Object Oriented Programming then call and apply will make sense if you compare it with inheritance and override the properties or method/functions of parent class from child class. Which is similar with call in javascript as following:
function foo () {
this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
console.log(this.helloworld)
}
foo.prototype.main = function () {
this.print()
}
function bar() {
this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
console.log(this.helloworld)
}
var iamfoo = new foo()
iamfoo.main() // prints: hello from foo
iamfoo.main.call(new bar()) // override print and prints: hello from bar

I can't think of any normal situation where setting the thisArg to something different is the purpose of using apply.
The purpose of apply is to pass an array of value to a function that wants those values as arguments.
It has been superseded in all regular everyday usage by the spread operator.
e.g.
// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`
// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2);
// which becomes
arr1 = [...arr2, ...arr1]

Related

chaining call and bind with slice() to convert array-like objects to arrays [duplicate]

I am having some trouble wrapping my head around this function:
var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​​​
How does this function accept an argument as seen in line 2?
Well,
Function.prototype.call references the "call" function, which is used to invoke functions with chosen this values;
The subsequent .bind refers to the "bind" function on the Function prototype (remember: "call" is a function too), which returns a new function that will always have this set to the passed-in argument.
The argument passed to "bind" is the "toString" function on the Object prototype, so the result of that whole expression is a new function that will run the "call" function with this set to the "toString" function.
The result, therefore, is like this code: Object.prototype.toString.call( param ). Then, the "console.log" call passes that function an array, and there you have it.
edit Note that Object.prototype.toString.call( param ) is like param.toString() really, when "param" is an object. When it's not, then the semantics of the "call" function are to turn it into one in the normal ways JavaScript does that (numbers -> Number, strings -> String, etc).
edit, 24 May2016 — That last sentence above is not accurate with ES2015. New JavaScript runtimes do not "autobox" primitive types when those are involved with a function call as a this value.
I assume you already know what .call and .bind do
toStr is now a function that essentially does:
function toStr( obj ) {
return Function.prototype.call.call( Object.prototype.toString, obj );
}
I.E it .calls the .call function with context argument set to the .toString function. Normally that part is already taken care of because you normally use .call as a property of some function which sets the function as the context for the .call.
The two lines of code are a function definition and then execution call of that definition with an empty array passed inside. The complexity lies in interpreting what 'this' will point to and why.
To help deduce the value of this I copied content from two links below to MDN's definitions of call and bind.
The bind() function creates a new function (a bound function) with the same function body as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(). Your code looks similar to a 'shortcut function' described on the bind page.
var unboundSlice = Array.prototype.slice; // same as "slice" in the previous example
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
With call, you can assign a different this object when calling an
existing function. this refers to the current object, the calling
object.With call, you can write a method once and then inherit it in
another object, without having to rewrite the method for the new
object.
When toStr is called it passes in an array to bind, of which the this pointer is bound.
With bind(), this can be simplified.
toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated.
In essence, it looks like a shortcut function override to the toString method.
JS to English translation -
var toStr = Function.prototype.call.bind( Object.prototype.toString );
The bind creates a new call function of Object.prototype.toString.
Now you can call this new function with any context which will just be applied to Object.prototype.toString.
Like this:
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​
Why not just calling Object.prototype.toString.call([]) ??
Answer:
Of course, you could. But the OPs method creates a dedicated and de-methodized function just for this purpose.
This really is called demethodizing.
bind() - Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.
Read this documentation for more information about bind() in JavaScript
Angular example:
Parent component where we have a defined function and bind it to an object:
public callback: object;
constructor() {
this.callback= this.myFunction.bind(this);
}
public myFunction($event: any) {
// Do something with $event ...
}
(Parent html) passing the binded object to child component:
<child-component (callbackFunction)="callback($event)"></child-component>
Child component that receives the object that is bind to the parent function:
#Output() callbackFunction: EventEmitter<object> = new EventEmitter<object>();
public childFunction() {
...
this.callbackFunction.emit({ message: 'Hello!' });
...
}
You could do :
var toStr = Object.prototype.toString.call([]);
Problem with this is : call executes instantly.
What you want is to delay the execution of call.
*As function is an object too in Javascript, you can use any function as the first argument in 'call' instead of passing an object as 1st argument.*Also, you can use the dot on call like on any object.
Function.prototype.call.bind( Object.prototype.toString ) , makes a copy of the call function with it's 'this' sets to Object.prototype.toString .
You hold this new copy of call function in 'toStr'.
var toStr = Function.prototype.call.bind( Object.prototype.toString );
Now you can executes this new copy of call any time you need without the need of setting 'this' as it's 'this' is already bind to Object.prototype.toString .
This should make sense to you
Object.prototype.toString.call([]) //work well
You think this form is too long and cumbersome and you want to simplify it? This makes it easier to use later:
const toStr = Object.prototype.toString.call
toStr([]) // unfortunately, this does not work
You need to use bind to correct where this points to.
const toStr = Object.prototype.toString.call.bind(Object.prototype.toString)
toStr([]) //work well
Object.prototype.toString.call is just the same as Function.prototype.call
const toStr = Function.prototype.call.bind(Object.prototype.toString)
toStr([]) //done
summary
function f(){console.log(this, arguments)}
f.call is just the same as Function.prototype.call.bind(f)
f.call(1,2,3) is just the same as Function.prototype.call.bind(f,1)(2,3)

Passing argument from one function to another

I'm wondering if this way of passing an argument from one function to another (let's say from f1 to f2):
f1 = function(arg){
f2(arg);
}
f2 = function(arg){
//doing sth with passed argument
}
Is wrong? Or is it better/safer to always use the .apply() method, even if we're not passing an array?
To clarify- argument is passed only to f1, and only from f1 f2 is called.
No, it's not wrong.
Passing parameters through functions is one of the fundamental aspects of JavaScript as a language. It helps you take a complex application and break it down into manageable chunks for both clarity and maintainability.
.apply is useful when you want to call a function with a specific scope ( that's why the first parameter is this ) and it takes an array or array-like secondary parameter for arguments to be used within the function. The fact that it's an array/array-like makes no difference at all to you as a programmer or to the function that you're calling. There's nothing special about it, it's just the format that apply expects.
Nothing wrong about that at all. This happens all the time.
The only reason you should use apply() is if you need what it does, like changing the context (value of this) or passing an array as individual arguments. You aren't doing anything like that here, so there is absolutely no reason to make more complicated.
When you declare an argument in JavaScript it's treated just like a variable, and you can use it like any other variable: reassign values, pass it to another function, etc. .apply(this, arguments) is also possible, but it's not necessary unless you need to set the this of the called function or to pass an arbitrary number of arguments.
The apply() method takes arguments as an array.
The apply() method is very handy if you want to use an array instead of an argument list.
<!DOCTYPE html>
<html>
<body>
<h2>JavaScript Functions</h2>
<p>In this example the fullName method of person is <b>applied</b> on person1:</p>
<p id="demo"></p>
<script>
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"John",
lastName: "Doe",
}
var x = person.fullName.apply(person1, ["Oslo", "Norway"]);
document.getElementById("demo").innerHTML = x;
</script>
</body>
</html>
While if you use two function and call One in another:
function function_one() { function_two(); }
function function_two() {
//enter code here
}
Function parameters are the names listed in the function definition.
Function arguments are the real values passed to (and received by) the function.
Parameter Rules
JavaScript function definitions do not specify data types for parameters.
JavaScript functions do not perform type checking on the passed arguments.
JavaScript functions do not check the number of arguments received.
Parameter Defaults
If a function is called with missing arguments(less than declared), the missing values are set to: undefined
more information JavaScript you can read this link
https://developer.mozilla.org/it/docs/Web/JavaScript

Defining a object's property based onanother object's property

I define an object called anotherObject with a function called anotherFunction based on the someFunction from the object someObject.
var someObject={
someFunction:function(){
return this;
}
};
console.log(someObject.someFunction()===someObject);//true
var someFunc=someObject.someFunction;
console.log(someFunc===someObject.someFunction);//true
//the function does not have the same context as that of the function called earlier...
console.log(someFunc()===someObject);//false
var anotherObject={
anotherFunction:someObject.someFunction
};
console.log(anotherObject.anotherFunction===someObject.someFunction);//true
console.log(anotherObject[anotherFunction]()===anotherObject);//true;
console.log(anotherObject.anotherFunction()===someObject);//false
Firefox Scratchpad reports that the function anotherFunction is not defined.
That's the way JavaScript functions actually work, the someFunction is a function which its responsibility is to return the this in the current context, no matter what is for this one:
var someFunc=someObject.someFunction;
you can call it using call or apply with whatever context you like:
var myobj = {};
console.log(someFunc.call(myobj)===myobj);//true
console.log(someFunc.apply(myobj)===myobj);//true
no matter what you pass as the first argument in call and apply, your function would return that very object. So as you see your function does what it is supposed to do, but if you want it to always return your first object someObject, you do not need to use this keyword.
Read my answer to the How does JavaScript .prototype work?, I have tried to dig into this concept in the first two parts.
And also this is one of the best resources you can find about this concepts:
Understanding JavaScript Function Invocation and “this”

How does Function.prototype.call.bind work?

I am having some trouble wrapping my head around this function:
var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​​​
How does this function accept an argument as seen in line 2?
Well,
Function.prototype.call references the "call" function, which is used to invoke functions with chosen this values;
The subsequent .bind refers to the "bind" function on the Function prototype (remember: "call" is a function too), which returns a new function that will always have this set to the passed-in argument.
The argument passed to "bind" is the "toString" function on the Object prototype, so the result of that whole expression is a new function that will run the "call" function with this set to the "toString" function.
The result, therefore, is like this code: Object.prototype.toString.call( param ). Then, the "console.log" call passes that function an array, and there you have it.
edit Note that Object.prototype.toString.call( param ) is like param.toString() really, when "param" is an object. When it's not, then the semantics of the "call" function are to turn it into one in the normal ways JavaScript does that (numbers -> Number, strings -> String, etc).
edit, 24 May2016 — That last sentence above is not accurate with ES2015. New JavaScript runtimes do not "autobox" primitive types when those are involved with a function call as a this value.
I assume you already know what .call and .bind do
toStr is now a function that essentially does:
function toStr( obj ) {
return Function.prototype.call.call( Object.prototype.toString, obj );
}
I.E it .calls the .call function with context argument set to the .toString function. Normally that part is already taken care of because you normally use .call as a property of some function which sets the function as the context for the .call.
The two lines of code are a function definition and then execution call of that definition with an empty array passed inside. The complexity lies in interpreting what 'this' will point to and why.
To help deduce the value of this I copied content from two links below to MDN's definitions of call and bind.
The bind() function creates a new function (a bound function) with the same function body as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(). Your code looks similar to a 'shortcut function' described on the bind page.
var unboundSlice = Array.prototype.slice; // same as "slice" in the previous example
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
With call, you can assign a different this object when calling an
existing function. this refers to the current object, the calling
object.With call, you can write a method once and then inherit it in
another object, without having to rewrite the method for the new
object.
When toStr is called it passes in an array to bind, of which the this pointer is bound.
With bind(), this can be simplified.
toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated.
In essence, it looks like a shortcut function override to the toString method.
JS to English translation -
var toStr = Function.prototype.call.bind( Object.prototype.toString );
The bind creates a new call function of Object.prototype.toString.
Now you can call this new function with any context which will just be applied to Object.prototype.toString.
Like this:
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​
Why not just calling Object.prototype.toString.call([]) ??
Answer:
Of course, you could. But the OPs method creates a dedicated and de-methodized function just for this purpose.
This really is called demethodizing.
bind() - Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.
Read this documentation for more information about bind() in JavaScript
Angular example:
Parent component where we have a defined function and bind it to an object:
public callback: object;
constructor() {
this.callback= this.myFunction.bind(this);
}
public myFunction($event: any) {
// Do something with $event ...
}
(Parent html) passing the binded object to child component:
<child-component (callbackFunction)="callback($event)"></child-component>
Child component that receives the object that is bind to the parent function:
#Output() callbackFunction: EventEmitter<object> = new EventEmitter<object>();
public childFunction() {
...
this.callbackFunction.emit({ message: 'Hello!' });
...
}
You could do :
var toStr = Object.prototype.toString.call([]);
Problem with this is : call executes instantly.
What you want is to delay the execution of call.
*As function is an object too in Javascript, you can use any function as the first argument in 'call' instead of passing an object as 1st argument.*Also, you can use the dot on call like on any object.
Function.prototype.call.bind( Object.prototype.toString ) , makes a copy of the call function with it's 'this' sets to Object.prototype.toString .
You hold this new copy of call function in 'toStr'.
var toStr = Function.prototype.call.bind( Object.prototype.toString );
Now you can executes this new copy of call any time you need without the need of setting 'this' as it's 'this' is already bind to Object.prototype.toString .
This should make sense to you
Object.prototype.toString.call([]) //work well
You think this form is too long and cumbersome and you want to simplify it? This makes it easier to use later:
const toStr = Object.prototype.toString.call
toStr([]) // unfortunately, this does not work
You need to use bind to correct where this points to.
const toStr = Object.prototype.toString.call.bind(Object.prototype.toString)
toStr([]) //work well
Object.prototype.toString.call is just the same as Function.prototype.call
const toStr = Function.prototype.call.bind(Object.prototype.toString)
toStr([]) //done
summary
function f(){console.log(this, arguments)}
f.call is just the same as Function.prototype.call.bind(f)
f.call(1,2,3) is just the same as Function.prototype.call.bind(f,1)(2,3)

Javascript: How to access a public variable in the same class?

I recently started programming JavaScript and thought everything would be good...
Well today I faced a problem I can't solve on my own.
My tutorial/ learning project has a class called model. In this class there are several private and one public variable. This variable is of type CustomEvent:
function Model(){
/**
* Array in which the questions are stored
*/
var questions=new Array();
var db;
var valuesSplit="*";
var tableName="quests";
this.myEvent=new CustomEvent("my event");
So as you can see "myEvent" is public and can be called from outside. In this case it is an event which can be subscribed (this is done outside this class by other objects that want to listen) and it can be fired (this is done in the same class). And this is my problem.
How can I access myEvent within the model class?
I tried:
this.myEvent.fire()
and:
myEvent.fire()
But I always get "myEvent is not defined".
Probably the first thing to say is: JavaScript doesn't have classes. The sooner you stop thinking of "JavaScript classes," the better off you'll be. :-) JavaScript has OOP, but not the kind with classes. Your Model function is called a constructor function.
You can access myEvent from any code that has a reference to the object created by new Model, which includes code in your constructor (via this — e.g., the way you're setting it up) and any function called with this referring to that object (or, of course, "externally" via someObjReference.myEvent).
So probably this.myEvent.fire() is what you want, but the code you're calling it from doesn't have the right this value. That's because in JavaScript, this is controlled entirely by how a function is called, not where the function is defined as it is in some other languages. See my blog articles Mythical methods and You must remember this for more details, but I've done a somewhat truncated discussion below.
Here's an example of a fairly standard way to set up a constructor function with useful methods that all instances share:
function Foo() {
this.myEvent = new CustomEvent("my event");
}
Foo.prototype.bar = function() {
this.myEvent.fire();
};
// Usage:
var f = new Foo();
f.bar(); // Fires the event indirectly, via the code in `bar`
f.myEvent.fire(); // Fires it directly
Note that that only works if bar is called with this referring to an object with a myEvent property. It's easy to call bar with this set to something else entirely:
document.getElementById("someID").onclick = f.bar;
When the click occurs, the bar function gets called, but this does not refer to an object created via Model. (It will refer to the element with the id "someID" instead.) And so this line in bar
this.myEvent.fire();
...will fail.
If you're used to class-based languages, you can see how this is totally different from, say, Java, C#, or C++. In those langauges, this inside bar will always refer to an object created via new Model. Not so JavaScript, which is both awkward and powerful.
This flexibility of functions (not being bound to any particular object) is one of the biggest things to get used to, and take advantage of, in JavaScript. The other is how functions are closures, which is powerful but not complicated.
So if this is set by how a function is called, how do you do that? There are two ways:
Call the function by referencing it from an object property in the same expression as the call. That's an awkward way of saying do this:
var f = new Foo();
f.bar(); // <== The key bit
f["bar"](); // <== Also works
The expression f.bar() does two things, which interact: The first thing it does is retrieve the property bar of the object referenced by f, and get that property's value (which is a function reference). Then it calls that function (because of the ()). The way JavaScript works, because you did those two things in the same overall expression, the interpreter sets this to f during the call to bar for you. But note this key distinction:
var f = new Foo();
var b = f.bar;
b(); // <== Different!
Now when the bar function gets called, this will not be set to f (it'll be set to the global object, which is window on browsers), because we've separated the property retrieval from the function call.
Alternately, you can use the built-in features of JavaScript function objects, their call and apply functions. call and apply do exactly the same thing, the only difference between them is how you supply the arguments for the function. Example:
var f = new Foo();
f.bar(1, 2): // <== Calls `bar` with `this` === `f` and passing in
// the arguments 1 and 2
var b = f.bar;
b.call(f, 1, 2); // <== Does the same thing as f.bar(1, 2)
var args = [1, 2];
b.apply(f, args); // <== Does the same thing as f.bar(1, 2)
E.g., call and apply allow you to set what this should be explicitly when you call the function. The only difference between them is that call accepts the arguments to give the function as further arguments to call, and apply accepts them as an array.
If you want to use myEvent in a non public function in your Model than you have to create another reference to the myEvent which isn't using the this reference of your Model. Because the this in another function is something else than in your Model function. The easiest way to bypass this problem is if you define a new variable in your Model:
var that = this;
Then you can call your myEvent like:
that.myEvent
The myEvent member should be visible both in the inner & outer scope of the object :
function Model(){
this.myEvent = 'some value';
this.canAccessEvent = function(){
return 'myEvent' in this;
}
}
var m = new Model();
// access from outside :
alert(m.myEvent);
// access from inside :
alert('Model can access the even? ' + m.canAccessEvent());
However, it is very possible that your new CustomEvent function doesn't exist or does not return a valid object making your myEvent variable to be undefined. I suggest you attribute some other value to the myEvent property and see if it is defined. If it is defined, then the problem lies in your CustomEvent function.

Categories

Resources