Skip to content Skip to sidebar Skip to footer

Lost Reference To Self When Using Knockoutjs And Simple Class Inheritance

I am using John Resig's 'Simple JavaScript Inheritance' to create a class that can be inherited. I am also using KnockoutJS for computed observables. The problem comes in trying

Solution 1:

I've never had any experience with KnockoutJS. However I'm well versed with inheritance in JavaScript and I frown upon John Resig's "Simple JavaScript Inheritance" pattern (primarily because it doesn't have private variables). Instead I prefer using my own class pattern. I think you might find it interesting:

window.mynamespace.myclass = newClass(function (uber) {
    var self = this;

    functionconstructor() {
    }

    this.someProperty = ko.observable(10);

    this.someComputedProperty = ko.computed(function () {
        return self.someProperty();
    });

    return constructor;
});

You may also use your method and simply skip creating self. Since the class is not created from an object you may use this within your class definition (something you can't do in John Resig's "Simple JavaScript Inheritance" pattern):

window.mynamespace.myclass = newClass(function (uber) {
    functionconstructor() {
    }

    this.someProperty = ko.observable(10);

    this.someComputedProperty = ko.computed(function () {
        return self.someProperty();
    }, this);

    return constructor;
});

You may also add methods directly to window.mynamespace.myclass.prototype. That way instead of returning self.someProperty() you may return myclass.prototype.someProperty(). Feel free to ask me if you need any help with my class pattern.

Edit:

The Class constructor has two parameters: a function defining the class and an optionalbase class to derive from. The first argument (i.e. the function) must return another function which is the constructor of the class (similar to a C++ or Java constructor).

Let's create a simple Rectangle class:

varRectangle = newClass(function () {
    // width and height are private variablesvar width;
    var height;

    // the class constructor accepts two argumentsfunctionconstructor(length, breadth) {
        // save the parameters
        width = length;
        height = breadth;
    }

    // area is a public functionthis.area = function () {
        // return the area of the rectanglereturn width * height;
    };

    return constructor; // always remember to return the constructor
});

Now you can create instances of the class Rectangle as demonstrated in this fiddle.

Now let's do something more fun - inheritance. The second parameter of the Class constructor is the base class to derive from. Let's create a class Square which derives from the class Rectangle.

// notice that the class definition function accepts a parameter called ubervarSquare = newClass(function (uber) {
    // return the constructor of the class Squarereturnfunction (side) {
        // call the base class constructor - uberuber(side, side);
    };
}, Rectangle); // Square derives from Rectangle

This is where things get interesting. Okay so we have 4 types of data members in this class pattern: private, public, shared, and static. We have already seen private and public data members.

Shared data members are those properties defined on the prototype of a class. They are shared by all instances of the class.

Static data members are those properties defined on the class itself. They are not inherited by the instances of the class.

In the above example when Square derives from Rectangle it inherits all the shared and static data members of Rectangle. In fact we may also define a new shared or static data member on RectangleafterSquare is defined and it will still be inherited by Square. Let's demonstrate this concept using an example:

alert(Square.staticDataMember); // staticDataMember is undefined
Rectangle.staticDataMember = "It works!"; // define staticDataMember on Rectangle
alert(Square.staticDataMember); // staticDataMember is inherited from Rectangle

The above is for static data members. Let's see the same for shared data members:

var square = newSquare(5); // create an instance of Squarealert(square.sharedDataMember); // sharedDataMember is undefinedRectangle.prototype.sharedDataMember = 0; // define sharedDataMember on Rectanglealert(square.sharedDataMember); // sharedDataMember is inherited from Rectangle

You may see the output of the above program in the following fiddle.

That's cool, but what about private and public data members? How are they inherited? Well, private and public data members are not inherited when we create a new class. They are inherited when create a new instance of a class. This is because different instances of the same class have different private and public data members.

When we create an instance of a derived class (like Square) we don't inherit the private and public data members of it's base class (i.e. Rectangle) until we call the base class constructor (i.e. uber). Only when we call the base class constructor are the private and public data members inherited (actually only the public data members are inherited - the others are called private for a reason):

varSquare = newClass(function (uber) {
    returnfunction (side) {
        alert(this.area); // area is undefineduber(side, side); // inherit public members from an instance of Rectanglealert(this.area); // area is now defined
    };
}, Rectangle);

You may see the output of the above program in the following fiddle.

Now let's create another class for kicks, and while we're at it we'll also demonstrate multilevel inheritance:

varCube = newClass(function (uber) {
    var side; // the length of a side of the cubefunctionconstructor() {
        side = arguments[0]; // save the first argument passed to the constructor
        uber = uber(side); // call the base constructor and save its instance
    }

    this.area = function () {
        return6 * uber.area(); // return the surface area of the cube
    };

    this.volume = function () {
        return side * uber.area(); // return the volume of the cube
    };

    return constructor; // remember to return the constructor
}, Square); // derive from Square

This is something new. Here we created a new area function which shadowed the area function defined in Rectangle, but what if we wanted to access the base class methods from the derived class?

Well, when we call the base class constructor (i.e. uber) it returns the instance of the base class. Since we don't need the base class constructor anymore we save the instance as uber. Then we may call the base class area method using uber.area as seen in the area and volume functions.

You may see the output of the above program in the following fiddle.

Thus you may see that this class pattern is much more powerful than John Resig's "Simple JavaScript Inheritance" pattern, and the Class constructor is only 47 lines of code (without being minified).

Solution 2:

You could always add them in the init. In knockout's own examples they do their binding in the constructor.

window.mynamespace.myclass = Class.extend({
    init: function() {
        this.someProperty = ko.observable(10);
        this.someComputedProperty = ko.computed(function() {
           returnthis.someProperty();  
        }, this);  
    }
});

Or capturing a reference to this and forgetting about binding:

window.mynamespace.myclass = Class.extend({
    init: function() {
        varself = this;
        self.someProperty = ko.observable(10);
        self.someComputedProperty = ko.computed(function() {
           returnself.someProperty();  
        });  
    }
});

Edit:

To demonstrate how you'd extend the class:

window.mynamespace.myotherclass = window.mynamespace.myclass.extend({
    init: function() {
      // do anything myotherclass init, like another observablethis.someOtherProperty = ko.observable(10);

      // incidentally you *can* have private variables with this patternvar imPrivate = 1;
      this.getImPrivate = function() {
        return imPrivate;
      };

      // then call super (maybe with arguments, maybe just passing them)this._super('foobar');
    }
});

Post a Comment for "Lost Reference To Self When Using Knockoutjs And Simple Class Inheritance"