0

I expect this results in console: "2" and "11". But instead it gives me "2" and "2". Why publicFunc2 is not overriden? http://jsfiddle.net/17b5ytmq/1/. I guess I don't understand something about subclassing in Javascript.

function MyClass() {
    var self = this;
    this._protectedArr = [1];
    this.publicFunc = function() {
        this._protectedArr.forEach(function(element, index, array) {
            console.log(element + self.publicFunc2());
        });
    }
    this.publicFunc2 = function () {
        return 1;
    }
}

function MyClassChild() {
    this.publicFunc2 = function () {
        return 10;
    }
}

var myClass = new MyClass();
myClass.publicFunc();

MyClassChild.prototype = myClass;
var myClassChild = new MyClassChild()
myClassChild.publicFunc();
user1561346
  • 502
  • 3
  • 13
  • 28
  • 2
    Because you're using the cached `self` reference to the original object instead of the `this`, which would be the caller defined object. –  Dec 19 '14 at 14:40
  • @squint But I can't use `this` in callback. How to deal with it? – user1561346 Dec 19 '14 at 14:41
  • `.forEach()` accepts a second argument to define the `this` value of the callback, so pass `this` after the callback. ...like this: http://jsfiddle.net/17b5ytmq/2/ –  Dec 19 '14 at 14:41
  • Mmh, might not be a duplicate after all, but you are sharing the same `this._protectedArr` instance across all instances. See http://stackoverflow.com/a/15041274/218196 for some info. You are setting up inheritance incorrectly. I recommend to read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance – Felix Kling Dec 19 '14 at 14:43
  • @squint what if callback don't accept second argument? – user1561346 Dec 19 '14 at 14:44
  • 1
    @user1561346: Not sure what you mean. It's `.forEach()` that accepts the second argument. Check out the demo. `this._protectedArr.forEach(function(element, index, array) { console.log(element + this.publicFunc2()); }, this); // <---` –  Dec 19 '14 at 14:45
  • 1
    If you meant that it's a different situation where you can't set the `this` value of the callback that way, then you can use `.bind()` or just create your `self` variable *inside* the `this.publicFunc()` like this: `this.publicFunc() { var self = this; this._protectedArr.forEach(func...` –  Dec 19 '14 at 14:47
  • @squint, now I get it. Thank you very much! – user1561346 Dec 19 '14 at 15:01

1 Answers1

1

You should inherit the prototype and not the instance like so:

MyClassChild.prototype = Object.create(MyClass.prototype);

also you should call the constructor function to truly inherit all of the class

function MyClassChild() {
    MyClass.call(this);

    this.publicFunc2 = function () {
        return 10;
    }
}

MyClassChild.prototype = Object.create(MyClass.prototype);

lastly, the this keyword is a dynamic reference to the current instance when used in methods.

when you assign this to a variable you create a static reference to the current instance that can be used like a reference to any other object.

Here is an explanatory example:

function MyClass() {
    var self1 = this;
    this.id = 'MyClass';

    this.publicFunc = function() {
        var self2 = this;
        asyncAction(function () {
            // self1 - MyClass
            // self2 - MyClass or MyClassChild - depends on the calling object
        });

        return self1.id + ' - ' + this.id;
    };

    this.publicFunc2 = function () {
        return 1;
    };
}

function MyClassChild() {
    MyClass.call(this);
    this.id = 'MyClassChild';

    this.publicFunc2 = function () {
        return 10;
    }
}
MyClassChild.prototype = Object.create(MyClass.prototype);

var myClass = new MyClass();
var myClassChild = new MyClassChild();

myClass.publicFunc(); // MyClass - MyClass
myClassChild.publicFunc(); // MyClass - MyClassChild

myClass.publicFunc2(); // 1
myClassChild.publicFunc2(); // 10
MrBar
  • 950
  • 6
  • 15
  • `self1` will be the `MyClassChild` instance as well when the constructor was called through the "super" `MyClass.call(this)`. You would usually need only one of the `self`s. – Bergi Dec 31 '17 at 15:43