0

I wanna create instance of object in javascript. I try to pass two function references to another class's constructor. But it throws error like below:

this.onFailFunction is not a function

But, If I pass just one reference (onSuccess) it works. What is difference?

index.html

<script>

            function onSuccess(data, message)
            {
                console.log(data);
                console.log(message);
            }


            function onFail(data, message, errorCode)
            {
                console.log(data);
                console.log(message);
                console.log(errorCode);
            }
            var callBack = new EbookCallBack(onSuccess, onFail);
            callBack.mainCallback.callSuccessFunction({success:false, message:"Wovvv", errorcode:1, data:"asdsa"});

        </script>

ebookcallback.js

class EbookCallBack 
{

    constructor(onSuccessFunction, onFailFunction) 
    {
        this.onSuccessFunction = onSuccessFunction;
        this.onFailFunction = onFailFunction;
        this.mainCallback = new CallBack(this.onSuccess, this.onError);
    }

    onSuccess(result) 
     {
        if(result.success)
        {
            this.onSuccessFunction(result.data, result.message);
        }
        else
        {
            this.onFailFunction(result.data, result.message, result.errorcode);
        }
    }

    onError(message) 
    {
        if(this.onErrorFunction !== undefined) 
        {
            this.onErrorFunction(message);
        } 
    }


}

maincallback.js

class CallBack 
{

    constructor(onSuccessFunction, onErrorFunction) 
    {
        this.onSuccessFunction = onSuccessFunction;
        this.onErrorFunction = onErrorFunction;
    }

    callSuccessFunction(data) 
    {
        this.onSuccessFunction(data);
    }

    callErrorFunction(message) 
    {
        this.onErrorFunction(message);
    }

}

3 Answers 3

3

Your problem starts at this part:

this.mainCallback = new CallBack(this.onSuccess, this.onError);

Because it will pass the function this.onSuccess and this.onError (which isn't defined anyway) without any connection to the EbookCallBack object, so later the this in this functions refers to the global object and not to the EbookCallBack anymore.

So if callSuccessFunction is called on CallBack, and this function will call this.onSuccessFunction(data), which then calls the onSuccess function you originally passed from the EbookCallBack, but this function will be called in the context of the global object and not in the one of the EbookCallBack.

You would need to use bind.

this.mainCallback = new CallBack(this.onSuccess.bind(this), this.onError.bind(this) );

(this.onError.bind(this) would right now fail, because onError is not defined)

Sign up to request clarification or add additional context in comments.

Comments

1

"this" is being lost. Inside EbookCallback,

onSuccess(result) 
 {
    if(result.success)
    {
        this.onSuccessFunction(result.data, result.message);
    }
    else
    {
        this.onFailFunction(result.data, result.message, result.errorcode);
    }
}

I set up a breakpoint in chrome devtools and when you get to this.onFailFunction, "this" is of the CallBack class, not the EbookCallback class. That's because when you call this.onSuccessFunction(data);, the context is set to the CallBack object

You can fix "this" by replacing new CallBack(this.onSuccess, this.onError); with new CallBack(this.onSuccess.bind(this), this.onFailFunction.bind(this));


EDIT

It occurs to me that nobody provided a potential alternative to 'bind'

this.mainCallback = new CallBack(this.onSuccess, this.onError); could be changed to the following:

this.mainCallback = new CallBack(function(result){
    this.onSuccess(result);
}, function(message){
    this.onError(message);
});

This solution might be more intuitive for some.

3 Comments

Yes. EbookCallBack class is between index.html page's script and Callback class. I access reference of CallBack class by EbookCallBack class
@t.niese answered the question first. So, I accept his answer. Thank you too.
@hkaraoglu i editted my answer to provide an alternative solution
-1

This appears to be a binding problem. When you do this:

callErrorFunction(message) 
{
   this.onErrorFunction(message);
}

...you're calling the function in the EbookCallBack class, but your this variable is bound to the current object (Callback), even when you're executing code in a different class.

Basically, using this in javascript is extremely difficult and confusing. I generally recommend not doing it at all if you can help it. Lots of programmers try to write javascript as if it's Java and wrap everything inside objects, but you really don't need to do that at all! (Are you by any chance a Java coder in a previous life?)

An OOP style in javascript adds a lot of boilerplate and bugs with this. You may find a functional style a lot more readable and maintainable. Check this out:

//just a plain JS object, not a class
var myCallbacks = {
    onSuccess: function( data, message ) {
       //do something
    },
    onFail: function( data, message, errorCode ) {
       //do something else
    }
};

tryTheThing( "fish", myCallbacks );

function tryTheThing( data, myCallbacks ) {
   if ( data === "fish" ) {
      myCallbacks.onSuccess(data, "Yay");
   } else {
      myCallbacks.onFail(data, "boo", 51);
   }
}

Much simpler, right? No need for classes or this. Or even better, use Javascript Promises, which already encapsulate this behaviour:

tryTheThing( "fish" )
   .then( function( data, message ) {
      //success
   }).catch( function( data, message, errorcode ) {
      //fail
   });

function tryTheThing( data ) {
   return new Promise( function( resolve, reject ) { 
      if ( data === "fish" ) {
         resolve( data, "yay" );
      } else {
         reject( data, "boo", 51 );
      }
   });
}

Promises are a core part of javascript now and a great way to handle callbacks without polluting your function parameters!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.