PolymorphismPrince
PolymorphismPrince

Reputation: 307

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?

Upvotes: 1

Views: 72

Answers (4)

Bonestack
Bonestack

Reputation: 81

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);

Upvotes: 1

M_Farahmand
M_Farahmand

Reputation: 1044

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";
            }
        }

        ...

Upvotes: 0

Mark
Mark

Reputation: 92440

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 :

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:

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);

Upvotes: 3

GauravLuthra
GauravLuthra

Reputation: 1035

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.

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.

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

doAction(jerry.sayMoo.bind(jerry));

Upvotes: 1

Related Questions