So, after doing even more research on providing prototypal functions access to private data, I came across this article on the Safe Factory Pattern. It is actually similar to my Accessor Verification pattern that I recommended here on Monday. The quick summary is that by shortening this a bit, you can actually safely achieve private data access from prototypal functions:


(function(global, returnData, undefined) {
  // Variable returnData is for temporarily storing what
  // will be returned from the openMySafe function.
  // "undefined" is defined this way so that to minify it
  // in closure compiler.
  
  // Gets the private data from the safe that was created
  // and returns it.
  function openMySafe(me) {
    returnData = undefined;
    me._();
    return returnData;
  }

  // Determine if caller is a property when a function is
  // executed.
  function callerExists() {
    return !!callerExists.caller;
  }
  callerExists = callerExists();
  
  // Returns a function that will return the provided
  // private data only when returnData evaluates to true.
  function makeMySafe(privateData) {
    function safe() {
      // If the caller of this function is openMySafe,
      // assign privateData to returnData.
      if(callerExists == (safe.caller == openMySafe)) {
        returnData = privateData;
      }
    };
    return safe;
  }
  
  // Create the Person class in the global namespace.
  var PersonPrototype = (global.Person = function(firstName, lastName) {
    this._ = makeMySafe({
      firstName : firstName,
      lastName : lastName
    });
  }).prototype;
  PersonPrototype.getName = function() {
    var pData = openMySafe(this);
    return pData.firstName + ' ' + pData.lastName;
  };
  PersonPrototype.setFirstName = function(firstName) {
    var pData = openMySafe(this);
    pData.firstName = firstName;
    return this;
  };
  PersonPrototype.setLastName = function(lastName) {
    var pData = openMySafe(this);
    pData.lastName = lastName;
    return this;
  };
})(this);

// Test out the code.
var chris = new Person('Chris', 'West');
alert(chris.setFirstName('C.').setLastName('Webber').getName());

// Make sure the private data is not accessible.
var prefix = chris._() === undefined ? 'un' : '';
// Outputs:  "The private data returned is undefined."
alert('The private data returned is ' + prefix + 'defined.');

This Abbreviated Safe Factory Pattern works for the following reasons:

  • The makeMySafe({private_data}) function takes the private data associative array object and uses encapsulation to return a function (safe function) which can assign the value to be returned by a safe opener function.
  • JavaScript is only arguably single-threaded (web-workers and browser events may be the exception but this doesn’t seem to be explicitly stated); no two threads can run at the same time.
  • Since JavaScript is single-threaded (or at least one function should execute fully before another starts), we can rely on one control value to determine when private data can be returned by the safe functions.
  • The openMySafe({person_object}) function…
    1. takes a person object
    2. sets returnData to undefined
    3. calls the safe function produced by makeMySafe({private_data}) (AKA {person_object}._()) to assign the private data object to returnData
    4. returns the value of returnData which should be the private data object

I actually had to add an if statement to the safe function due to the existence of Function.prototype.caller. Without this if statement, rogue code could get a reference to openMySafe which would effectively provide access to the private data of an object. This is actually a deficiency that even exists in the original Safe Factory Pattern

If multiple threads could run at once it would be possible for the incorrect private data to get passed back to the wrong class instance. If you do have to allow your classes to multi-threaded, I would recommend using the Accessor Verification Pattern I suggested in this post.

Again, I invite all JavaScripters to try to find a way to get the private data without modifying the closure. I am personally convinced that using this Abbreviated Safe Factory Pattern is a fullproof way of allowing prototypal functions access to truly private members. If you can find a way to disprove me, though, I would be thoroughly impressed (and would much appreciate it)! 8)


8 Comments

ildar · April 3, 2013 at 2:01 PM

Two examples of the bad performance in both cases. I tried to simplify examples as much as possible.

Example 1.
Consider two constructors X and Y are declared in the same file.
Y emulates inheritance of X.

[code language=javascript]
(function (global, returnData, undefined) {
function openMySafe(me) {
return returnData = 1, me = me._(), returnData = undefined, me;
}

function makeMySafe(privateData) {
return function () {
return returnData && privateData;
};
}

function X() {
this._ = makeMySafe({
value: 'X'
});
};

X.prototype.get = function () {
var x = openMySafe(this);
alert(x.value);
};

global.X = X;

function Y() {
X.call(this);
this._ = makeMySafe({
value: 'Y'
});
};

Y.prototype.get = function () {
// call of the parental inherited method
X.prototype.get.call(this);

var x = openMySafe(this);
alert(x.value);
};

global.Y = Y;

})(this);

var x = new Y();
x.get();
[/code]

Example 2.
Consider constructors X and Y are declared in different files.
Y continues to emulate inheritance of X

[code language=javascript]
(function (global, returnData, undefined) {
function openMySafe(me) {
return returnData = 1, me = me._(), returnData = undefined, me;
}

function makeMySafe(privateData) {
return function () {
return returnData && privateData;
};
}

function X() {
this._ = makeMySafe({
value: 'X'
});
};

X.prototype.get = function () {
var x = openMySafe(this);
alert(x.value);
};

global.X = X;

})(this);

(function (global, returnData, undefined) {
function openMySafe(me) {
return returnData = 1, me = me._(), returnData = undefined, me;
}

function makeMySafe(privateData) {
return function () {
return returnData && privateData;
};
}

function Y() {
X.call(this);
this._ = makeMySafe({
value: 'Y'
});
};

Y.prototype.get = function () {
// call of the parental inherited method
X.prototype.get.call(this);

var x = openMySafe(this);
alert(x.value);
};

global.Y = Y;

})(this);

var x = new Y();
x.get();
[/code]

    Chris West · April 4, 2013 at 12:34 AM

    I was thinking about posting this in a separate page, but I think for now this is fine. The following is an example using a safe factory and also prototypal inheritance:
    [code language=javascript]
    (function(global, returnData, undefined) {
    // Variable returnData controls whether or not the private
    // data function returns data.

    // Assigns 1 to returnData, calls the provided object's
    // private data function to get the data and then sets
    // returnData back to undefined.
    function openMySafe(me) {
    return returnData = 1, me = me._(), returnData = undefined, me;
    }

    // Returns a function that will return the provided
    // private data only when returnData evaluates to true.
    function makeMySafe(privateData) {
    return function() {
    return returnData && privateData;
    };
    }

    // Create the Person class in the global namespace.
    var PersonPrototype = (global.Person = function(firstName, lastName) {
    this._ = makeMySafe({
    firstName : firstName,
    lastName : lastName
    });
    }).prototype;
    PersonPrototype.getName = function() {
    var pData = openMySafe(this);
    return pData.firstName + ' ' + pData.lastName;
    };
    PersonPrototype.setFirstName = function(firstName) {
    openMySafe(this).firstName = firstName;
    return this;
    };
    PersonPrototype.setLastName = function(lastName) {
    openMySafe(this).lastName = lastName;
    return this;
    };
    PersonPrototype.toString = function() {
    return 'Name: ' + this.getName();
    };

    // Create a `Male` class which inherits the Person prototype functions.
    var MalePrototype = (global.Male = function() {
    Person.apply(this, arguments);
    openMySafe(this).sex = "male";
    }).prototype = new Person;

    // Define a new `getSex()` function for this class.
    MalePrototype.getSex = function() {
    return openMySafe(this).sex;
    };

    MalePrototype.toString = function() {
    var pData = openMySafe(this);
    return Person.prototype.toString.call(this) + 'nSex: ' + pData.sex;
    };
    })(this);

    // Create two people.
    var resig = new Male("John", "Q."),
    crockford = new Person("Douglas", "Crockford");

    // Show John's full name.
    alert(resig.getName());

    // Change John's last name and then show his full name.
    alert(resig.setLastName("Resig").getName());

    // Show all of Resig's info.
    alert(resig.toString());

    // Show all of Crockford's info.
    alert(crockford.toString());
    [/code]

    This example is pretty much a mix of the code I used above and the code from this post. Hopefully this helps you understand a little bit better how you can have prototypal inheritance and still have the safe factory.

ildar · April 4, 2013 at 4:32 PM

Ok. Let’s talk about strict, classical inheritance. Follow this link. http://javascript.ru/forum/66098-post2.html. There is simple and very good library implementing classical OOP in JS. The constructor’s property “superclass” allows to refer to the parent’s prototype. So this allows to call parental methods

Take it and replace all global properties “this.foo” and “this.bar” with private data. And check results. Modify your code if you declared A and B within different files (or different scopes). Below is simple example. You know what to do further 🙂

[code language=javascript]
var B = A.inherit({
constructor: function(foo) {
B.superclass.constructor.apply(this, arguments);
this._ = makeMySafe({
bar: foo + 1
});
},

alert: function() {
B.superclass.alert.apply(this, arguments);
var pData = openMySafe(this);
alert(pData.bar);
}
});
[/code]

    Chris West · April 4, 2013 at 10:16 PM

    I will look at that in a little bit, but I believe I learned the method of inheritance that I am using in my example from either Dean Edward’s blog or Douglas Crockford (like shown here).

      ildar · April 5, 2013 at 12:10 AM

      OO inheritance by the page I have provided is almost the same as Dean Edward’s. In fact, it doesn’t matter how we implement the classical inheritance. We just need to have the valid prototypal chain for the link “instance <- Y(child class) <- X(parent class)".

      The root problem is that the "openMySafe" function and the "this._" method are called in different scopes and the first one doesn't see changes made by the second one.

      Consider the next situation. You have two constructors "Person" and "Male". They are absolutely identical those above but declared in different scopes. You have two declarations within the same single scope. Separate them by wrapping each declaration within its own scope. And you will see those things I have meant.

      Shortly. Separating their declaration you will be able to simulate situation when the object instantiated from Y (working with its own private data) that is inherited from X (which works with its own private data).

ildar · April 6, 2013 at 11:26 AM

With your implementation of “private” data they can be stolen.

[code language=javascript]
(function(that) {
function openMySafe(me) {
return returnData = 1, me = me._(), returnData = undefined, me;
}

function makeMySafe(privateData) {
return function() {
return returnData &amp;&amp; privateData;
};
}

that.X = function() {
this._ = makeMySafe({
secret: 'I am private!'
});
};
X.prototype.alert = function() {
var p = openMySafe(this);
alert(p.secret);
};
})(this);

var x = new X();

(function(f) {
x._ = function() {
var p = f();
alert('I know your secret: ' + p.secret);
return p;
};
})(x._);

x.alert();
[/code]

If you really want to implement “private” data follow the recommendations given in the article http://www.codeproject.com/Articles/133118/Safe-Factory-Pattern-Private-instance-state-in-Jav . A function returning something can be overwritten so this leads to possibility of “private” data disclosure.

    Chris West · April 7, 2013 at 2:27 AM

    Hey Ildar. I just updated the code so now I believe the private data will not be retrievable. Thanks for the link, but that is actually the same one that I used in this post. I am glad that you are here to keep me in check! 8) I actually ended up discovering that by leveraging the Function.prototype.caller, one could steal the private data even when using the safe factories on the link you provided (which is also the same one I used in producing this post). For this reason, my updated code includes an extra check to basically make sure that only when the openMySafe calls the safe function that the private data will be stored in the returnData variable. Let me know if you have a way of even hacking this one. If you somehow do, I still have one more trick up my sleeve though. 😉

    P.S. Thank you very much for your contributions and diligence in checking the validity of my function calls!

      ildar · April 7, 2013 at 1:03 PM

      Hi Chris. Look at these pages:
      https://github.com/devote/jsClasses
      http://javascript.ru/forum/168029-post1.html

      I understand that those are in Russian and you will have troubles in understanding of the description. Anyway, you can use Google Translate and read examples. The main idea in the context of our discussion is ability of creating of real private data.

      I am not author of this idea and, in my opinion, his code is ugly, monstruous and very difficult to understand. It is the first point. The second point is absense of valid inheritance of “classes” — instantiating object “y” from “Y’ inherited from “X” we cannot check this using “y instanceof X” or “y instanceof Y”. The third point is complete impossibility of usage of this code in WSH.

Leave a Reply

Your email address will not be published. Required fields are marked *