How to pass a function that's a property of another object into a function and call it in javascript?

Multi tool use
How to pass a function that's a property of another object into a function and call it in javascript?
If I have an object in Javascript and one of its properties is a function:
function cow() {
this.timesMooed = 0;
this.sayMoo = function () {
this.timesMooed++;
return "moo";
};
}
Say I also have another function that takes some function as an argument, calls it and records the result:
var actionResults = ;
function doAction(action) {
actionResults.push(action());
}
Now let's put this into practice and see what happens:
var jerry = new cow();
doAction(jerry.sayMoo);
console.log(actionResults);
// Outputs ["moo"] -this is correct
console.log(jerry.timesMooed);
// Outputs 0 -uh oh
How can I pass in the function so that it's Jerry
that is running the function?
Jerry
doAction(jerry.sayMoo.bind(jerry));
This question has been asked and answered dozens, if not hundreds, of times on SO. Search and research harder.
– torazaburo
Jul 2 at 3:19
4 Answers
4
When you pass the reference to the function doAction
and then call it with action()
, the calling context changes and this is what determines the value of this
. You need to use bind
to keep the value of this
locked to jerry
:
doAction
action()
this
bind
this
jerry
function cow() {
this.timesMooed = 0;
this.sayMoo = function () {
this.timesMooed++;
return "moo";
}
}
var actionResults = ;
function doAction(action) {
actionResults.push(action());
}
var jerry = new cow();
// use bind, which makes a function with `this` set properly
doAction(jerry.sayMoo.bind(jerry));
console.log(actionResults);
console.log(jerry.timesMooed);
Alternatively you can use arrow functions =>
which bind this
lexically:
=>
this
function cow() {
this.timesMooed = 0;
// use arrow function here instead
this.sayMoo = () => {
this.timesMooed++;
return "moo";
}
}
var actionResults = ;
function doAction(action) {
actionResults.push(action());
}
var jerry = new cow();
// no need to bind() now
doAction(jerry.sayMoo);
console.log(actionResults);
console.log(jerry.timesMooed);
Brilliant answer!
– fuzz
Jul 2 at 2:49
This is exactly the depth that I wanted; thankyou so much for a clear and thorough answer!
– PolymorphismPrince
Jul 2 at 4:45
Problem is that this
keyword is used in a method and we call that method from a receiver object and this
is not bound to the object that we expect it to be bound to i.e. jerry in this case.
this
this
Note that this
value in methods and functions must be set explicitly when we need a specific object bound to the function’s this
value.
this
this
Solution
Solution is simple to use correct context
i.e. we want this
to refer to jerry hence while invoking doAction method with sayMoo method of jerry object use bind function call and pass jerry as this argument
this
doAction(jerry.sayMoo.bind(jerry));
try creating a constructor
class cow {
constructor(){
this.timesMooed = '';
}
sayMoo() {
this.timesMooed+=1;
return "moo";
}
}
var actionResults = ;
function doAction(action) {
actionResults.push(action);
}
var jerry = new cow();
doAction(jerry.sayMoo());
console.log(actionResults);
console.log(jerry.timesMooed);
This is good, except for the fact that (1) it's unnecessary and (2) it address the OP's issue--he want's to push the function call itself, to be executed later (with the right
this
), not the result of the function call.– torazaburo
Jul 3 at 2:49
this
As @Mark_M says the better way is to use arrow function but this feature force you to use ES6 instead of ES5 because bound function introduce in ES5.
Another way is to use benefits of variable scope like this:
function cow() {
this.timesMooed = 0;
var that = this;
this.sayMoo = function (){
that.timesMooed++;
return "moo";
}
}
...
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
doAction(jerry.sayMoo.bind(jerry));
– ASDFGerte
Jul 2 at 2:25