4

I'm doing some Javascript R&D and, while I've read Javascript: The Definitive Guide and Javascript Object Oriented Programming, I'm still having minor issues getting my head out of class based OOP and into lexical, object based OOP.

I love modules. Namespaces, subclasses and interfaces. w00t. Here's what I'm playing with:

var Classes = {
    _proto : {
        whatAreYou : function(){
            return this.name;
        }
    },
    Globe : function(){
        this.name = "Globe"
    },
    Umbrella : new function(){
        this.name = "Umbrella"
    }(),
    Igloo : function(){
        function Igloo(madeOf){
            this.name = "Igloo"
            _material = madeOf;
        }
        // Igloo specific
        Igloo.prototype = {
            getMaterial : function(){
                return _material;
            }
        }
        // the rest
        for(var p in Classes._proto){
            Igloo.prototype[p] = Classes._proto[p]
        }
        return new Igloo(arguments[0]);
    },
    House : function(){
        function House(){
            this.name = "My House"
        }
        House.prototype = Classes._proto
        return new House()
    }
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto

$(document).ready(function(){    
    var globe, umb, igloo, house;

    globe     = new Classes.Globe();
    umb       = Classes.Umbrella;
    igloo     = new Classes.Igloo("Ice");
    house     = new Classes.House();

    var objects = [globe, umb, igloo, house]

    for(var i = 0, len = objects.length; i < len; i++){
        var me = objects[i];
        if("whatAreYou" in me){
            console.log(me.whatAreYou())
        }else{
            console.warn("unavailable")
        }
    }
})

Im trying to find the best way to modularize my code (and understand prototyping) and separate everything out. Notice Globe is a function that needs to be instantiated with new, Umbrella is a singleton and already declared, Igloo uses something I thought about at work today, and seems to be working as well as I'd hoped, and House is another Iglooesque function for testing.

The output of this is:

Globe
unavailable
Igloo
My House

So far so good. The Globe prototype has to be declared outside the Classes object for syntax reasons, Umbrella can't accept due to it already existing (or instantiated or... dunno the "right" term for this one), and Igloo has some closure that declares it for you.

HOWEVER...

If I were to change it to:

var Classes = {
    _proto : {
        whatAreYou : function(){
            return _name;
        }
    },
    Globe : function(){
        _name = "Globe"
    },
    Umbrella : new function(){
        _name = "Umbrella"
    }(),
    Igloo : function(){
        function Igloo(madeOf){
            _name = "Igloo"
            _material = madeOf;
        }
        // Igloo specific
        Igloo.prototype = {
            getMaterial : function(){
                return _material;
            }
        }
        // the rest
        for(var p in Classes._proto){
            Igloo.prototype[p] = Classes._proto[p]
        }
        return new Igloo(arguments[0]);
    },
    House : function(){
        function House(){
            _name = "My House"
        }
        House.prototype = Classes._proto
        return new House()
    }
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto

$(document).ready(function(){    
    var globe, umb, igloo, house;

    globe     = new Classes.Globe();
    umb       = Classes.Umbrella;
    igloo     = new Classes.Igloo("Ice");
    house     = new Classes.House();

    var objects = [globe, umb, igloo, house]

    for(var i = 0, len = objects.length; i < len; i++){
        var me = objects[i];
        if("whatAreYou" in me){
            console.log(me.whatAreYou())
        }else{
            console.warn("unavailable")
        }
    }
})

and make this.name into _name (the "private" property), it doesn't work, and instead outputs:

My House
unavailable
My House
My House

Would someone be kind enough to explain this one? Obviously _name is being overwritted upon each iteration and not reading the object's property of which it's attached.

This all seems a little too verbose needing this and kinda weird IMO.

Thanks :)

5
  • 2
    because your "private" is global. Commented Jan 12, 2012 at 12:09
  • I originally had the var keyword in there, but missed putting it back in. That's why you don't ask questions at 3am ;) In any case, thank you for your responses, it makes a bit more sense now and the same solution applies. Cheers! Commented Jan 12, 2012 at 17:39
  • You might be interested in ES5 OO sugar Commented Jan 12, 2012 at 17:51
  • I've seen and used some of these libraries that allow for a more structured class OOP-style usage, but I still need to understand the language. Thanks though, I'm always lookin for good libs. Commented Jan 12, 2012 at 17:53
  • The article lists prototypical OO mechanisms. Not dirty classical OO emulations. My personal favourite is combining extend and Object.create Commented Jan 12, 2012 at 17:59

2 Answers 2

5

You declare a global variable. It is available from anywhere in your code after declaration of this. Wherever you request to _name(more closely window._name) you will receive every time a global. In your case was replaced _name in each function. Last function is House and there has been set to "My House"

Declaration of "private" (local) variables must be with var statement.

Check this out:

var foo = function( a ) { 
    _bar = a;
    this.showBar = function() { 
       console.log( _bar );
    }
};
var a = new foo(4);   // _bar ( ie window._bar) is set to 4

a.showBar(); //4


var b = new foo(1); // _bar  is set to 1
a.showBar(); //1
b.showBar(); //1

_bar = 5; // window._bar = 5; 
a.showBar();// 5

Should be:

var foo = function( a ) { 

    var _bar = a;
    // _bar is now visibled only from both that function
    // and functions that will create or delegate from this function,
    this.showBar = function() { 
       console.log( _bar );
    };
    this.setBar = function( val ) { 
        _bar = val;
    };
    this.delegateShowBar = function() { 
       return function( ) { 
           console.log( _bar );
       }
    }
};
foo.prototype.whatever = function( ){ 
    //Remember - here don't have access to _bar
};

var a = new foo(4);
a.showBar(); //4

_bar // ReferenceError: _bar is not defined  :)
var b = new foo(1);

a.showBar(); //4
b.showBar(); //1

delegatedShowBar  = a.delegateShowBar();
a.setBar(6);
a.showBar();//6
delegatedShowBar(); // 6
Sign up to request clarification or add additional context in comments.

Comments

1

If you remove the key word "this", then the _name is in the "Globe" scope.

Looking at your code.

var globe, umb, igloo, house;

globe     = new Classes.Globe();
umb       = Classes.Umbrella;
igloo     = new Classes.Igloo("Ice");
house     = new Classes.House();

At last the house will override the "_name" value in globe scope with the name of "My House".

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.