0

I want to call the parent function with the same context (ie..this) in a child.

I'v done some research on this, and haven't come up with good results. The ones that I have tried have resulted in not being able to read property of undefined errors. Here is my code (I have simplified and remove lots of code to shorten) :

test if the function I want to call. I have made comments in the code.

CHILD

function LiveChat(userID) {
        var _this = this;
        Buoy.call(this);
        this.init = function () {
            this.cacheDom();
            this.bindEvents();
        };
        this.cacheDom = function () {
            this.$userInput = this.$buoy.find(".user-chat-input");
            this.$conversationArea = this.$buoy.find(".conversation-area");
            this.$loading = this.$buoy.find(".loading");
        };
        this.bindEvents = function () {
            this.$userInput.on("input", this.setConversationAreaY.bind(this));
            this.$userInput.on("keydown", this.sendMessage.bind(this));
            this.$conversationArea.on("scroll", this.loadOlderMessages.bind(this));
            this.$buoy.on("click", this.focusInput.bind(this));
        }

        //I WANT TO CALL TEST IN PARENT
        //KEEPING THE CORRECT CONTEXT WITH .CALL(THIS)

        this.init();
    }

PARENT

/* Buoy Class */
    function Buoy() {
        this.buoyID = 'buoy-' + getHoverID();
        this.init = function () {
            this.cacheDom();
            this.bindEvents();
        };
        this.cacheDom = function () {
            this.$buoy = $buoyContainer.find("#" + this.buoyID);
            this.$buoyHeader = this.$buoy.find(".header");
            this.$closeBuoy = this.$buoyHeader.find(".close-button");
        };
        this.bindEvents = function () {
            this.$closeBuoy.on("click", this.closeBuoy.bind(this));
            this.$buoyHeader.on("click", this.toggleBuoyMinimize.bind(this));
            this.$buoy.on("click", this.focusBuoy.bind(this));
            $(document).on("mousedown", this.unfocusBuoy.bind(this));
        };

        this.test = function(){
            //THIS IS WHAT I WANT TO CALL
        }

        this.init();
    };

EXTEND FUNCTION

function extend(Child, Parent) {
    var Tmp = function () {
    };
    Tmp.prototype = Parent.prototype;
    Child.prototype = new Tmp();
    Child.prototype.constructor = Child;
}

    extend(LiveChat, Buoy);
    extend(AddDream, Buoy);
  • How come you know how to call `init` but not know how to call `test`? – Bergi May 13 '17 at 07:37
  • Your `extend` function is outdated. You should just use `Child.prototype = Object.create(Parent.prototype);` instead of that `Tmp` thing. – Bergi May 13 '17 at 07:38
  • @Bergi I changed my code to what Curtismorte said below. I am still getting the error 'cannot read property call of undefined'. Calling Buoy.test.call(this); – user7965134 May 13 '17 at 15:46
  • You might try ECMAScript6 (probably in conjunction with BabelJS to support older systems) and then simply check my other post regarding this topic: http://stackoverflow.com/questions/28627908/es6-call-static-methods/43694337#43694337 – Thomas Urban May 13 '17 at 16:32
  • @user7965134 `Buoy.test` does not exist. I guess you're looking for a simple `this.test()`, although I'm not exactly sure *where* you want to call the `test` method – Bergi May 13 '17 at 19:35

1 Answers1

-1

You want LiveChat to extend Bouy.

Vanilla JavaScript doesn't provide syntax sugar to handle polymorphism pre ES6 - so you have to extend it yourself.


I have used your code to explain the current issue you are facing which is you didn't create an object from Parent.prototype in your extend function before applying it to Child.prototype. In Addition, your functions were defined as named functions which could not be referenced prior to initialization.

I have simplified and fixed your extend function which was the precursor to your initial problem. To "call the parent function with the same context (ie..this) in a child", just add this.test() inside of LiveChat.

For correctness, JavaScript didn't have classes until ES6 (and presently the class declaration isn't widely supported).

Follow the comments as you go:

// PARENT FUNCTION
var Buoy = function() {

    this.init = function () {
      console.log('Buoy - init');
    };
    this.cacheDom = function () {
      console.log('Buoy - cacheDom');
    };
    this.bindEvents = function () {
      console.log('Buoy - bindEvents')
    };

    this.test = function(){
       console.log('Buoy - Test');
       console.log('What is my context', this);
    }
    
};

// CHILD FUNCTION
var LiveChat = function(userID) {
    
    // The instance for LiveChat is passed to
    // Bouy, where the methods attached in Bouy
    // are added to the LiveChat instance before
    // the methods below are added 
    Buoy.call(this);
    
    // POLYMORPHISM... dun dun dun! :p
    
    this.init = function () {
      console.log('LiveChat - init');
    };
    this.cacheDom = function () {
      console.log('LiveChat - cacheDom');
    };
    this.bindEvents = function () {
      console.log('LiveChat - bindEvents');
    }
    
    //I WANT TO CALL TEST IN PARENT
    //KEEPING THE CORRECT CONTEXT WITH .CALL(THIS)

    // You don't need to use .call(this) because the test
    // method already has the LiveChat context
    this.test();
}

function extend(Child, Parent) {
    // ---------------------
    // YOUR PROBLEM WAS HERE:
    // ---------------------
    
    // Create a new object from the Parent.prototype
    // That allows all the values saved to the Parent
    // scope to be preserved in the child scope
    Child.prototype = Object.create(Parent.prototype);
    
    // Changing the constructor for child means that
    // calling new Child() will result in LiveChat
    // being the constructor to execute
    Child.prototype.constructor = Child;
}

// LiveChat extends Buoy
extend(LiveChat, Buoy)

// Create a new instance of LiveChat
var liveChat = new LiveChat();
  • What would the problem with his current `extend` function? And I don't see him using `Object.prototype` anywhere – Bergi May 13 '17 at 07:40
  • @Bergi - That's a typo. It should be Function.prototype. Updating now! Thank you – curtismorte May 13 '17 at 16:15
  • @user7965134, did you change from named functions? From my original answer: Your functions were defined as named functions (```function Buoy(){}```), which could not be referenced until after they had been initialized (```var bouy = new Bouy();```). Creating a variable with a function as its value allows you to access the function without an instance of the function first. – curtismorte May 13 '17 at 16:18
  • @curtismorte Just for clarity. I want to be able to call test function from inside of the livechat class. – user7965134 May 13 '17 at 16:19
  • @user7965134 the updates were in the description, not the code. – curtismorte May 13 '17 at 16:19
  • @user7965134 your methods inside of the function Bouy and LiveChat should be placed on the scope of the instance like you have (```this.init()```). The change needs to come where you define the named functions Bouy and LiveChat in your example. Here is how it should be done ```var LiveChat = function(userID){ ... }``` – curtismorte May 13 '17 at 16:26
  • @curtismorte I made the changes. I am still getting the error when calling "Buoy.test.call(this);" inside of the LiveChat function. – user7965134 May 13 '17 at 16:33
  • @curtismorte He is not using `Function.prototype` either? And no, all usages of `.prototype` properties in `extend` are fine (though `Tmp` is outdated). – Bergi May 13 '17 at 19:34
  • @Bergi, you're right. I was referencing prototype, but it should have been from Parent or Child and not specific to the actual 'Function.prototype'. Thanks again. – curtismorte May 13 '17 at 21:46
  • @user7965134 if you're trying to call ```Buoy.test.call(this);``` from inside of LiveChat, you just have to call test like this: ```this.test()```. Remember, LiveChat extends Buoy, so by definition it will have the test method on it's context unless it is overwritten (in your case it is not). – curtismorte May 13 '17 at 22:16
  • @user7965134 run the code snippet and you will see that it works. – curtismorte May 13 '17 at 22:16