0

Trying to learn how to create a durable object with JavaScript, but as you can see from the example below one can easily access any of the Person instance's members - What am I doing wrong?

function Person(name, age, job){
    "use strict";

    //create the object to return
    var o = new Object();

    //optional: define private variables/functions here
    o.name  = name;
    o.age   = age;
    o.job   = job;

    //attach methods
    o.sayName = function(){
        alert(name);
    };    

    //return the object
    return o;
}

var newGuy = Person("Guy", 21, "Seeker");

newGuy.name; // "Guy" <- Shouldn't this return an error or "undefined"?
  • 1
    related (not an *exact* duplicate): [Javascript: Do I need to put this.var for every variable in an object?](http://stackoverflow.com/q/13418669/1048572) for the difference between local variables and properties of an object (regardless whether you use a constructor+`this` or your `o`). – Bergi Aug 16 '14 at 19:07

3 Answers3

2

You get "Guy" because you set it as name property of o, and then return o to the outside, making it public.

If you want private variables, you can use

function Person(name, age, job){
    "use strict";
    // name, age, job are private variables
    // sayName is a privileged method
    this.sayName = function(){
        alert(name);
    };
}
var newGuy = new Person("Guy", 21, "Seeker");
newGuy.name; // undefined

Note you don't need to create a new o object and return it, just call the constructor with new operator and assign public/privileged properties to this.

I suggest reading Private Members in JavaScript, by Douglas Crockford.

Oriol
  • 274,082
  • 63
  • 437
  • 513
  • So is it safe to say that as long as I do not return the "private" variables anywhere they will remain private? What is the difference between using the new keyword and not doing so with regard to Durable Constructors? The reason I ask is that according to the book I am reading, "Professional: JavaScript for Web Developers, Third Edition" by Nicholas Zakas - says "A durable constructor... is never called using the new Operator." – user1809836 Aug 16 '14 at 18:57
  • 1
    If you use the pattern than calls for new and defines properties on `this`, they will be part of the object that is returned by default. The durable constructor pattern by definition avoids `this` and `new`. Instead it explicitly returns only methods and no visible data members. So in your example instead of assigning properties to 'o' you will assign methods to o that have privileged access to private variables within in the function. When you return o, it won't have any properties other than the methods you defined—these are the only route to the private data. – Mark Aug 16 '14 at 19:30
  • 1
    See also for durable constructors: http://www.yuiblog.com/blog/2008/05/24/durable-objects/ – Mark Aug 16 '14 at 19:32
1

There are a lot of different ways to create private properties. They all find ways to take advantage of the fact that variables are scoped locally within functions, but can be captured in functions.

For example rather than returning o, which will have all the properties exposed, you can return a different object that has private access. There's a bit of redundancy in this snippet, but I wanted to keep it close to your example:

function person(name, age, job){
     "use strict";
    //optional: define private variables/functions here
    var name  = name;
    var age   = age;
    var job   = job;

   //return the object that uses variable, that are only visible within the function
   return {
        sayName: function(){
                    alert(name);
                    },
        sayJob: function(){
                    alert(job);
                    }
   }
}

var newGuy = person("Guy", 21, "Seeker");

newGuy.sayName();   
newGuy.sayJob();   
alert("undefined: ", newGuy.name); // "Guy" <- Shouldn't this return an error or "undefined"?
Mark
  • 90,562
  • 7
  • 108
  • 148
1

For a durable object, Douglas Crockford recommends avoiding "this" and "new" altogether. This is how you would go about accomplishing what you want:

var person = function (vals) {
    var that = {}; // create object to avoid constructing with "new" and using "this"

    that.sayName = function () { // bind accessor functions
        return vals.name; // use passed values to ensure privacy
    };

    return that;
};

var guy = person({name: "Guy"}); // avoided use of "new"
alert(guy.name); // undefined as should be
guy.sayName(); // "Guy"

You can find more info in his book: Javascript: The Good Parts on page 52. I hope this helps.