Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript inheritance problem when using prototypes - instances overwritten :(

I'm new to JavaScript programming and I am having a bit of a nightmare with inheritance. I am writing some code for Appcelerator Titanium and I have a base class called Slide2D that I wish to inherit from.

So I have placed a few functions in Slide2D's prototype. These are generally not going to be overwritten, but will be called from classes derived from Slide2D. These functions will also be called from other parts of the program. There are also various eventhandlers used to manage animation in Titanium.

If I make a couple of these slides in some calling code (using new)

var s = new Slide2D('slide1', 'background1.png', etc......
var t = new Slide2D('slide2', 'background2.png', etc......

all of my prototype methods point to the last Slide2D created, regardless of whether I use s or t. So 'slide2' will always be displayed, even if I'm using the s variable.

This is driving me mad - any help would be greatly appreciated.

Sorry for the length of the code but here it is:

function Slide2D(name, backgroundImage, transform, inAnimation, outAnimation)
{
Titanium.API.info('Slide2D - Constructor - ' + name);

var _self = this;

var _name = name;

var _backgroundImage = backgroundImage;

var _startingTransform = transform;

var _slideView = Titanium.UI.createView({
    backgroundImage: _backgroundImage,
    transform: transform
});

    var _animateInAnimation = Titanium.UI.createAnimation();
_animateInAnimation.transform = Titanium.UI.create2DMatrix().translate(0,0);
_animateInAnimation.duration = 750;

var _animateOutAnimation = Titanium.UI.createAnimation();
_animateOutAnimation.transform = Titanium.UI.create2DMatrix().translate(-1024,0);
_animateOutAnimation.duration = 750;

var onAnimateInStart = function()
{
    Titanium.API.info('Slide2D.onAnimateInStart');
    Titanium.App.fireEvent('animateInStart', {slideName: _name});

    _animateInAnimation.removeEventListener('start', onAnimateInStart);
};

var onAnimateOutStart = function()
{
    Titanium.API.info('Slide2D.onAnimateOutStart');
    Titanium.App.fireEvent('animateOutStart', {slideName: _name});

    _animateInAnimation.removeEventListener('start', onAnimateOutStart);
};

var onAnimateInComplete = function()
{
    Titanium.API.info('Slide2D.onAnimateInComplete');
    Titanium.App.fireEvent('animateInComplete', {slideName: _name});

    _animateInAnimation.removeEventListener('complete', onAnimateInComplete);
};

var onAnimateOutComplete = function()
{
    Titanium.API.info('Slide2D.onAnimateOutComplete');
    Titanium.App.fireEvent('animateOutComplete', {slideName: _name});

    _animateOutAnimation.removeEventListener('complete', onAnimateOutComplete);
};

_animateInAnimation.addEventListener('start', onAnimateInStart);
_animateOutAnimation.addEventListener('start', onAnimateOutStart);

_animateInAnimation.addEventListener('complete',onAnimateInComplete);
_animateOutAnimation.addEventListener('complete', onAnimateOutComplete);

Slide2D.prototype.animateIn = function(){
    Titanium.API.info('Slide2D.prototype.animateIn - ' + _name);

    _slideView.animate(_animateInAnimation);
};

Slide2D.prototype.animateOut = function(){
    Titanium.API.info('Slide2D.prototype.animateOut');

    _slideView.animate(_animateOutAnimation);
};

    Slide2D.prototype.getName = function()
{
    return _name;
};

Slide2D.prototype.getView = function(){
    Titanium.API.info('Slide2D.prototype.getView');
    return _slideView;
};

Slide2D.prototype.getStartingTransform = function(){
    return _startingTransform;
};
 };

Edit

Thanks very much for your prompt reply. I have made the changes that you recommended and that has resolved that particular problem.

However, a new issue has been introduced.

I need to call Slide2D.prototype.getView from a derived class - ExtendedSlide2D.

However, now I get the following error :

Result of expression 'Slide2D.prototype.getView()' [undefined] is not an object
   at ExtendedSlide2D.js at line .......

This is where I add the button to the base class's view object.

I'm sure this error just comes down to my inexperience with the language but, once again, any help would be greatly appreciated.

Once again - here is the code for ExtendedSlide2D:

Titanium.include('Slide2D.js');



function ExtendedSlide2D(name, backgroundImage, transform, inAnimation, outAnimation)
{

Titanium.API.info('ExtendedSlide2D - Constructor');


this.base = new Slide2D(name, 
                            backgroundImage, 
                            transform, 
                            inAnimation,     
                            outAnimation);



ExtendedSlide2D.prototype.constructor = ExtendedSlide2D;



var button = Titanium.UI.createButton({title: 'AnimateOut',
                                           height: 40,
                                           width: 200,
                                           top: 50

});

button.addEventListener('click', function()

{
    Slide2D.prototype.animateOut();

});


Slide2D.prototype.getView().add(button);
}



ExtendedSlide2D.prototype = new Slide2D();
like image 390
Martin Avatar asked Feb 28 '11 07:02

Martin


People also ask

How does JavaScript prototype inheritance work?

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.

What kind of inheritance mechanism is used in JavaScript?

Prototypes are JavaScript's only inheritance mechanism: each object has a prototype that is either null or an object. In the latter case, the object inherits all of the prototype's properties.

Does JavaScript have inheritance?

Inheritance is an important concept in object oriented programming. In the classical inheritance, methods from base class get copied into derived class. In JavaScript, inheritance is supported by using prototype object.

What are some ways objects can inherit properties in JS?

In JavaScript, an object can inherit properties of another object. The object from where the properties are inherited is called the prototype. In short, objects can inherit properties from other objects — the prototypes.

How to understand prototypes and inheritance in JavaScript?

To understand prototypes and inheritance in JavaScript, you will need to understand these five points: Objects can have properties. Objects inherit properties from their prototype. Functions are objects which can also have properties. Functions have a prototype property. A function’s prototype is NOT the same thing as an object’s prototype.

How does inheritance work in JavaScript?

You can think of inheritance as a chain, each object’s prototype references the next link in the chain until it reaches the default object at the top of the chain, Object.prototype. Notice in the following code block we initialize an empty object using the object literal syntax and store a reference to that object in the variable obj.

What is the [prototype] reference in JavaScript?

Since [ [Prototype]] is linked to an object, that object has its own [ [Prototype]] reference. This is how a chain is built (it’s known as the prototype chain ). This chain of [ [Prototype]] is the building-block of inheritance in JavaScript. To access the object’s [ [Prototype]], most of the browsers provide a __proto__ property.

What is an object’s prototype?

An object’s prototype is a private property that each object has that references or points to its prototype (the object that it inherits from). According to the JavaScript documentation at ECMAScript, this internal property is called [ [Prototype]].


1 Answers

You'll need to move the methods that you adding to the prototype outside of the Slide2D constructor function. That way they only get defined once instead of with every object instantiation.

And then for those prototype functions to access the "internals", such as _name, _slideView, etc... You will need to convert all your "vars" (currently accessible under closure) to be properties of the object itself. Then reference all those member properties with a "this." prefix.

Below, I brute-forced replaced all your "vars" to be this.properties. Only the properties and function you need to access from the prototype methods need this conversion. For internal functions (such as your animate functions), they may still be able to use vars accessible under closure.

function Slide2D(name, backgroundImage, transform, inAnimation, outAnimation) {

    Titanium.API.info('Slide2D - Constructor - ' + name);

    _self = this;

    this._name = name;

    this._backgroundImage = backgroundImage;

    this._startingTransform = transform;

    this._slideView = Titanium.UI.createView({
        backgroundImage: this._backgroundImage,
        transform: transform
    });

    this._animateInAnimation = Titanium.UI.createAnimation();
    this._animateInAnimation.transform = Titanium.UI.create2DMatrix().translate(0, 0);
    this._animateInAnimation.duration = 750;

    /// ...

};

Slide2D.prototype.animateIn = function () {
    Titanium.API.info('Slide2D.prototype.animateIn - ' + this._name);

    this._slideView.animate(this._animateInAnimation);
};

Slide2D.prototype.animateOut = function () {
    Titanium.API.info('Slide2D.prototype.animateOut');

    this._slideView.animate(this._animateOutAnimation);
};

Slide2D.prototype.getName = function () {
    this._name;
};

Slide2D.prototype.getView = function () {
    Titanium.API.info('Slide2D.prototype.getView');
    this._slideView;
};

Slide2D.prototype.getStartingTransform = function () {
    this._startingTransform;
};
like image 127
selbie Avatar answered Sep 20 '22 07:09

selbie