6

I'm working on a utility to create classes in javascript. And it works, the problem is how to define private attributes.

This is the code

var OO = {

    Class:function(){

        var len = arguments.length;
        var data = arguments[len-1];



        var Klass;
        if (data.constructor === Object){
            Klass = function (){};

        } else {
            Klass = data.constructor;
            delete data.constructor;                
        }



        OO.extend(Klass.prototype,data); //Classic Extend Method


        return Klass;


    },
//Simple extend method, just what I need in this case
    extend: function(target, source){
            var prop;
            for (prop in source)
                target[prop] = source [prop];

    }
}

This is how it works

// first create a class
var person = OO.Class ({
constructor: function (name, age) {
this.name = name;
this.age = age;
},

name:'',
age:'',

getName: function () {
return this.name;
},

getAge: function () {
return this.age;
}

});

And here is the instance

var one = new Person ('josh', 22);

And the problem:

one.age / / returns 22
one.name / / returns josh

What I need is that these properties can only be accessed by methods like getName () and getAge ()

EDIT1: Added Extend Function

WSD
  • 3,243
  • 26
  • 38

4 Answers4

1

The closure is created by the constructor params, so this is all you need to do (edited AlienWebguy's code):

var Person = function(name, age){

    this.getName = function() {
        return name;
    };

    this.getAge = function() {
        return age;
    };

};

var john = new Person('johnathan', 33);

document.writeln(john.name);        // undefined
document.writeln(john.age);         // undefined
document.writeln(john.getName());   // johnathan
document.writeln(john.getAge());    // 33
Maverick
  • 3,039
  • 6
  • 26
  • 35
0

Update 1:

Here it the working prototype. It works except for

1.) Passing in construction values to private members.

 Dummy values do work however.

Test out the fiddle:

http://jsfiddle.net/UWRHP/11/

  • the extend implementation is posted! I want all the attributes private, so the user can't acces it directly via instance.attrib, he must define getters and setters. Any idea on how to do that ? – WSD Sep 07 '12 at 01:24
  • I'm sorry, but is a little bit hard to get online from here (I'm from the Caribbean). In response to your question, I've edited the original post since that implementation does not exist (by now). It's a future idea to try to extend from parent classes. – WSD Sep 08 '12 at 00:07
  • like I say before, it's hard to get online from here, so one more time apologize me, please write your implementation and the vote is for you. Thanks in advance. – WSD Sep 10 '12 at 15:44
  • @Josh - Here is way to create privacy I believe ( different approach al l together ). http://stackoverflow.com/questions/14491005/how-to-create-privacy-with-the-use-of-bind –  Jan 23 '13 at 23:12
-1

Any variable which is part of the object's interface (ie this.x and this.y) will be public. You will not be able to force access external access to those variables to go via the getters.

So, as long as you have code like this:

getAge: function () {
    return this.age;
}

... you cannot prevent this:

var one = new Person ('josh', 22);
console.log(one.age);

Check out Douglas Crockford's article Private Members in JavaScript.

Richard JP Le Guen
  • 28,364
  • 7
  • 89
  • 119
  • Based on my code... any idea of how to force attributes to be privates and only accesible via getters ? – WSD Sep 07 '12 at 01:26
  • Maybe it's too much to ask, but could you at least guide me, no matter what I have to redefine what I've done – WSD Sep 08 '12 at 00:12
  • @Jash Gazman - Have you taken a look at my other answer, or Stylez's more concise but similar answer? – Richard JP Le Guen Sep 08 '12 at 05:29
-1

If you're looking to not over complicate things (and completely ditch what you've done so far) as @AlienWebguy suggests, you don't even need the .io member - which in the end is exposed just as much as the .name and .age properties were:

john.io.set('name', 'Johnny'); // still exposed!

In the end, the .io object is just as exposed as the .name and .age properties, so it's a complicated solution which doesn't make any progress on encapsulation nor information hiding. (sorry, @AlienWebguy, that's just the way I feel)

If you're trying to use a classical inheritance paradigm and ditching conventional JavaScript OOP entirely, then ditch the conventional functions-as-constructors paradigm and forget about using the this reference in your constructors:

// first create a constructor
var Person = function(arg0, arg1) {

    var that = {};

    // private variables

    var age = arg0;
    var name = arg1;

    // public methods

    that.getName = function() {
        return name;
    };

    that.getAge = function() {
        return age;
    };

    that.setAge = function(a) {
        age = a;
    };

    return that;

};

var john = new Person('johnathan', 33);

console.log(john.name);        // undefined
console.log(john.getName());   // 'johnathan'
console.log(john.age);        // undefined
console.log(john.getAge());   // 33
john.setAge(28);
console.log(john.getAge());   // 28
john.setName("Richard");      // Error - setName is not a function

This is an example of Douglas Crockford's Parasitic Inheritance... but without the "inheritance" part. The point is, the instance variables age and name are private, but remain in scope because of JavaScript's functional variable scoping, so the object's methods can still manipulate them.

You'll also notice that the name variable has no setter, so this technique legitimately will allow you to control access to the name variable - there is no hidden this.name nor this.io which will allow the variable to be manipulated; it is entirely private.

Richard JP Le Guen
  • 28,364
  • 7
  • 89
  • 119