My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label private. Show all posts
Showing posts with label private. Show all posts

Thursday, September 09, 2010

JavaScript Protected Properties

Imagine this simple piece of code:

var obj = {
_name: "protected",
gimmeName: function () {
return this._name;
}
};

obj.gimmeName(); // "protected"
obj._name; // throws new Errror

now, imagine I have the simplest solution ever, compatible with both ES5 and ES3 genric implementations ... now please keep reading to know a bit of background :)


The JS Meaning Of Protected

JS developers know that in JavaScript properties are always public and that it is possible to attach/detach properties in any moment to a generic object. Regardless this fact, many libraries consider protected, by naming convention, all those properties whose name start with "_".


You Are Doing It Wrong

First of all I keep saying that is a common error trying to bring classical Object Oriented concepts into a completely different language as JavaScript is, but it does not matter ... we want protected stuff, right?
Due dynamic nature, the common protected meaning is pointless. See this example:

var obj = {
_name: "",
getName: function () {
return this._name;
},
setName: function (_name) {
this._name = _name;
}
};

getName and setName method are theoretically the only one able to change the _name property ... correct? Why, 'cause these are object methods ???

var obj.iCreateAnotherMethod = function (_whateverIWant) {
this._name = _whateverIWant;
};
obj.iCreateAnotherMethod(
"JS protected JOKE"
);

Now try to argue that a dynamic object with a dynamic associated method should not be able to perform the same operation setName does ...


At Least Do It Better!

All protected I have seen so far are quite prolix, inefficient, or pointless.
First of all, let's analyze the problem: what protected should be.
For protected we may consider all those properties or methods that should not be accessed directly but that can be accesses by public (or protected) methods of the same instance.
In few words, we would like to be sure that these properties are not easily accessible outside the object.


An ES5 Friendly Implementation



Object.defineProtectedProperty = (function (
defineProperty // from Object
) {
// (C) WebReflection - Mit Style License

// check that a caller is an object method
function check(object, caller) {
// this function accesses enumerable
// properties.
// returns instantly if check()
// was the property accessor
// (avoid recursion)
if (caller === check) {
return;
}
// avoid direct calls
// in the global scope
// ( or via apply/call )
if (caller) {
for (var key in object) {
if (
// the caller is a method
// ( property wrapper )
object[key] === caller
) {
return;
}
}
}
// if the method was not attached/inherited
// fuck up the execution with an error
throw "access denied";
}

// named expression (we like debugging)
return function defineProtectedProperty(
object, // the generic object
key, // the generic key
description // the ES5 style description
) {
// cache the value
var value = description.value;
// remove it since get/set + value
// does not make sense
delete description.value;
// define the getter
description.get = function get() {
check(object, get.caller);
return value;
};
// define the setter
description.set = function set($value) {
check(object, set.caller);
value = $value;
};
// define and return
return defineProperty(object, key, description);
};
}(Object.defineProperty));

Here some usage example:

// generic object
var o = {
greetings: function () {
this._sayHello();
}
};

// protected property
Object.defineProtectedProperty(
o, "_hello",
{value: "Hello World"}
);

// protected method
Object.defineProtectedProperty(
o, "_sayHello",
{enumerable: true, value: function () {
alert(this._hello);
}}
);

// method call
try {
o._sayHello();
} catch(e) {
alert(e); // access denied
}

// property access
try {
o._hello = "no way";
} catch(e) {
alert(e); // access denied
}

o.greetings(); // Hello World

The only thing to remember is that by default, enumerable is false so, if we would like to access a protected property inside a protected method, we must set it as enumerable so the for/in loop can discover it and verify it as object method.
Pros: compatible with all latest browsers, included IE9, with the only exception of WebKit and Safari (but I have already filed a bug there). It is possible to specify all defineProperty description, in this case except get and set.

Cons: not compatible with less recent browsers plus the check may cost if protected properties are constantly accessed. Address these properties once if it's needed to use them multiple time. Set them once as well if it's needed to change their value.


An ES3 Friendly Implementation

Here the version compatible with many other browsers, witohut the possibility to set ES5 properties such enumerable, configurable, and writable. It is also not possible to avoid a delete operation, which could cause problems.

Object.defineProtectedProperty = (function () {

// (C) WebReflection - Mit Style License

// check that a caller is an object method
function check(object, caller) {
// this function accesses enumerable
// properties.
// returns instantly if check()
// was the property accessor
// (avoid recursion)
if (caller === check) {
return;
}
// avoid direct calls
// in the global scope
if (caller) {
for (var key in object) {
if (
// the caller is a method
// ( property wrapper )
object[key] === caller
) {
return;
}
}
}
// if the method was not attached/inherited
// fuck up the execution with an error
throw "access denied";
}
return function defineProtectedProperty(
object, // the generic object
key, // the generic key
value // the generic description
// only value is considered
) {
value = value.value;
// define the getter
object.__defineGetter__(key, function get() {
check(object, get.caller);
return value;
});
// define the setter
object.__defineSetter__(key, function set($value) {
check(object, set.caller);
value = $value;
});
// return the object
return object;
};
}());

The same usage showed in the precedent example so that migration to ES5 version will be less painful.

Pros: compatible with almost all current browsers except IE family and WebKit/Safari due same bug reported before.

Cons: less secure than ES5 version since delete operation is allowed and properties then re-configurable. Other cons from ES5 version.


The caller Is Dead, Long Life to the Caller

In ES5 they keep removing powerful stuff considering all developers idiots unable to understand JS ... at least this is my feeling when I read things like "the with statement is dangerous" and "with 'use strict' caller should throw an error".
I don't really mind if they remove arguments.callee, we can always use function expressions (IE < 9 a part), but the genericFunction.caller is one of the most fundamental properties every function could possible have.
As instance, it wouldn't be even possible to think about my protected proposal without the caller, while internally all engines know who is the first level outer scope since they need it for variables resolution (e.g. when an inner scope uses an outer scope variable). Is this truly a performances issue? I don't think so, but I have not yet tested it so ... let's see ...


A Scoped Alternative For Every Browser

The only real private thing in JavaScript is a function scope, where this is private only from its outer scope, unless we don't hack it bringing there stuff via eval:

function toOuterScope($) {

var x = 1;

return eval($);
}

alert(toOuterScope("++x")); // 2
alert(typeof x); // undefined

Accordingly, the best way ever to ensure some sort of protection is to store properties into a private scope.
This is the alternative that works with every browser:

var scoped = (function () {

// (C) WebReflection - Mit Style License

// the only real private thing in JS
// is a function scope, like this one
// variables here are private/scoped as well
var
stack = [], // objects collection
id = [], // objects ids
n = -1, // object not found
// minifier shortcuts
indexOf = "indexOf",
push = "push",
splice = "splice"
;

// speed up the get(self, key)
// if indexOf returns -1 we don't care
// we return something from Object.prototype
stack[n] = {};

// ensure that outside nobody can change
// id or stack used Array.prototype methods
// (assignment rather than inherited chain)
id[push] = id[push];
id[splice] = (stack[splice] = id[splice]);
// for Jurassic browser implement a quick indexOf
id[indexOf] = id[indexOf] || function (value) {
for (var i = id.length; i--;) {
if (id[i] === value) {
break;
}
}
return i;
};

// unregister the object
// and all scoped properties
function clear(self) {
var i = id[indexOf](self);
if (n < i) {
id[splice](i, 1);
stack[splice](i, 1);
}
}

// retrieve the scoped property value
function get(self, key) {
// no shortcut to avoid lookup
// slightly better performances
return stack[id.indexOf(self)][key];
}

// set the scoped property value
function set(self, key, value) {
var i = id[indexOf](self);
if (n == i) {
stack[i = id[push](self) - 1] = {};
}
stack[i][key] = value;
}

// named function (we like debugging, don't we?)
function scoped(key, value) {
var
// verify who called the scoped function
caller = scoped.caller,
// improve minifier ratio
self = this,
// one var is enough, undefined is safer
property, undefined
;
// avoid direct calls
// e.g. obj.scoped()
// in a global context
if (caller) {
// loop them all
for (property in self) {
// check if object's method is the caller
if (self[property] === caller) {
// undefined or null key means clear(self)
return key == null ? clear(self) :
// value === undefined means get(self, key)
// otherwise means set(self, key, value)
value === undefined ?
get(self, key) :
set(self, key, value)
;
}
}
}
// if the method was not attached/inherited
// fuck up the execution with an error
throw "access denied";
}

// ready to go
return scoped;

}());

Above variable can be used as object property (method) or as prototype method without problems, and here we have some usage example:

// generic constructor
function F() {}

// scoped as prototype
F.prototype._scoped = scoped;
// getter
F.prototype.getProtected = function (key) {
return this._scoped(key);
};
// setter
F.prototype.setProtected = function (key, value) {
this._scoped(key, value);
};
// clear all scoped properties
F.prototype.clearProtected = function () {
this._scoped();
};

// generic instance
var f = new F;

// set protected
f.setProtected("test", 123);
alert(f.getProtected("test")); // 123

// re-set
f.setProtected("test", 456);
alert(f.getProtected("test")); // 456

// clear all
f.clearProtected();

alert(f.getProtected("test")); // undefined

// try to access scoped
try {
f._scoped();
//scoped.call(f, "whatever");
} catch(e) {
alert(e); // access denied
}

Less Magic With Methods

If we would like to reproduce initial code example, we should tweak the object in a weird way, e.g.


var o = {
_scoped: scoped,
init: function () {
var self = this;
self._scoped("_hello", "Hello World");
self._scoped("_sayHello", function _sayHello() {
self._sayHello = _sayHello;
alert(self._scoped("_hello"));
delete self._sayHello;
});
},
greetings: function () {
this._scoped("_sayHello")();
}
};

// call the init to set scoped properties
o.init();

try {
o._scoped("_sayHello")();
} catch(e) {
alert(e); // access denied
}

try {
o._scoped("_hello", "no way");
} catch(e) {
alert(e); // access denied
}

o.greetings(); // Hello World

This latest alternative is indeed ideal for properties but not methods.
Pros: compatible with basically every browser. No enumeration at all, detached properties.
Cons: not intuitive as other options. Properties must be set via init. We need to clear properties when we don't need the object anymore. Performances are not better than other options.


As Summary

Protected properties are closer here but still we should remember the runtime method that should logically be able to set a protected property ... this is JavaScript, not Java or C#, so probably we should be stuck with the idea that protected and private, in latter case scope talking a part, do not make sense and whatever we do can only decrease overall performances, too often granting a slightly better security.

Wednesday, October 22, 2008

a new Relator object plus unshared private variables

This is a Robert Nyman's post dedicated reply, about JavaScript inheritance and alternatives and private variables.

First of all, I would like to say thanks to Robert for both interesting articles He is writing about JS inheritance, and a link to a personal comment which aim was to bring there my "old" documentation about classical JavaScript inheritance and usage of prototype, closures, and public, privileged, or private, scope when we create a constructor.

About


Last Rob's post talk about private variables, describing them as shared, if present outside the constructor, and valid only for singleton instances.
This is true, and could cause a lot of headache if we are not truly understanding closures and prototype shared methods behaviour, but there is a way to use this peculiarity about shared private variables to create dedicated private variables.

Before I will write about it, let's look into a generic shared private variable example:

Click = function(){
// closure for private methods / variables

// private shared variable
var _total = 0;

// returned constructor + prototype
function Click(){};
Click.prototype.add = function(){
_total++;
};
Click.prototype.getTotal = function(){
return _total;
};
return Click
}();

var left = new Click,
right = new Click;

left.add();
alert(right.getTotal()); // 1

Above example shows that if a variable is created outside the constructor and prototype shared methods use that variable, every call to one of those method from a generic instance will modify that single private variable, created once inside that closure. To obtain a private variable we need privileged methods:

Click = function(){ // privileged methods
var _total = 0;
this.add = function(){
_total++;
};
this.getTotal = function(){
return _total;
};
};

var left = new Click,
right = new Click;

left.add();
alert(right.getTotal()); // 0

As discussed before in my doc, in robert's posts, and everywhere else in the web, privileged methods create many functions for each instance, and with big projects this is not good for both memory and CPU usage.

new Relator object and unshared private variables


The Relator is an object capable to relate a generic variable with a clear object, without modifying the original variable.
The classic example is this:

var myNum = 123;
Relator.set(myNum).description = "I am number 123";
alert(myNum.description); // undefined
alert(Relator.get(myNum).description); // "I am number 123"

Since with Relator it is possible to create a unique relation between a generic object and a private Object, it was natural for me to think that a private variable could be a Relator like object using this as unique relationship.
The new version of my Relator still respect the precedent API, being a Relator itself, but is now able to return a new object Relator like that could be used, as example, inside a closure.

// new Relator can create a Relator like object with method "$"
PrivateRelator = function(Relator){
// Relator argument is a new Relator like object
// present only in this scope
return {
get:function(what){
var value = Relator.get(what);
return value && value.value;
},
set:function(what, value){
Relator.set(what).value = value;
}
}
}(Relator.$()); // create a new Relator

Relator.set(window).value = "Hello World";
Relator.get(window).value; // Hello world
PrivateRelator.get(window); // undefined
PrivateRelator.set(window, "Hello Private World");
PrivateRelator.get(window); // Hello Private World
Relator.get(window).value; // Hello World

The good part of Relator is that the stored variable, if it is an object, is stored by reference, and we can assign more than a private unique relationship between a single object and our extra informations.
The same pattern could be easily re-adapted to create a shared private variables:

Person = function(){

// private methods
function _getName(){
return _private.get(this).name
};
function _setName(name){
_private.get(this).name = name;
};

// private variable, shared by every function in this scope
var _private = Relator.$();

// constructor + prototype
function Person(){
// bridge to _private shared variable
_private.set(this);
};
Person.prototype.getName = function(){
return _getName.call(this);
};
Person.prototype.setName = function(name){
_setName.call(this, name);
};
return Person;

}();

// extended constructor
function Enhanced(){
// necessary to save
// this instance into _private variable
// accessible only via Person scope
Person.call(this);
};
(function(){ // quick runtime extend
var callee = arguments.callee;
if(this instanceof callee)return;
callee.prototype = Person.prototype;
Enhanced.prototype = new callee;
})();


var me = new Person(),
rob = new Enhanced();

me.setName("Andrea");
rob.setName("Robert");

alert([me.getName(), rob.getName()]);
// Andrea,Robert


Conclusion


Sometime a limitation could be easily managed to obtain desired result.
In this case, thanks to JavaScript closures and its prototype nature, the shared variable become a sort of bridge to obtain private variables for each instance.
It is important to understand that even if we extend the base constructor, every new instance will still persist into original _private variable, inside the Person scope, unless we do not specify a different one, redefining every method that use that variable as well:

(function(_private){
Enhanced = function(){
_private.set(this);
};
(function(){ // quick runtime extend
var callee = arguments.callee;
if(this instanceof callee)return;
callee.prototype = Person.prototype;
Enhanced.prototype = new callee;
})();
Enhanced.prototype.getName = function(){
return _private.get(this).name
};
Enhanced.prototype.setName = function(name){
_private.get(this).name = name;
};
})(Relator.$());


See you soon ;)

Monday, April 07, 2008

Natural JavaScript private methods

I've never seen this technique yet, but basically it allows us to create private methods, without privileged, and in an way that does not allow subclasses to inherit them ... does it sound interesting? ;)

As we can read in my JavaScript Prototypal Inheritance for Classical Emulation documentation, there is a way to easily create private methods without usage of privileged.

The advantage of this way is, as explained in my doc, is that JavaScript interpreter does not have to create many functions for each declared instance.

Here there is a basic example:


// our constructor
function Person(name, age){
this.name = name;
this.age = age;
};

// prototype assignment
Person.prototype = (function(){

// we have a scope for private stuff
// created once and not for every instance
function toString(){
return this.name + " is " + this.age;
};

// create the prototype and return them
return {

// never forget the constructor ...
constructor:Person,

// "magic" toString method
toString:function(){

// call private toString method
return toString.call(this);
}
};
})();

// example
alert(
new Person("Andrea", 29)
); // Andrea is 29

Function toString will be shared by prototype with every created instance for the simple reason that every instance will inherit prototype.toString method and, at the same time, it points to private scope where toString function has been defined.
Is everything ok? Perfect, because we have to comprehend quite perfectly above example to understand what we are going to do right now ( and if you do not understand, read my doc to know more :P )

What we have to do each time is to remember that when we need a private method, with our instance injected scope, we have to write in an unnatural way.

What I mean is that if we usually use the underscore prefix to define our virtually protected methods, why couldn't we use them to define a function for private stuff only?

// our constructor
function Person(name, age){
this.name = name;
this.age = age;
};

// prototype assignment
Person.prototype = (function(){

// private stuff
function toString(){
return this.name + " is " + this.age;
};

// prototype
return {

constructor:Person,

toString:function(){

// call private toString method
// in a more natural way
return this._(toString)();
},

// define private methods dedicated one
_:function(callback){

// instance referer
var self = this;

// callback that will be used
return function(){
return callback.apply(self, arguments);
};
}
};
})();

// example
alert(
new Person("Andrea", 29)
); // Andrea is 29

The difference is basically in this line of code:


// instead of this way
return toString.call(this);

// we have this one
return this._(toString)();



Please do not forget that these methods are private, so there is no way to use them in subclasses, if those are created in an external or different closure, and that is exactly an expected behaviour (these functions are private).
But at the same time, if a subclass call an inherited method that use inside the parent prototype the private underscore, it will work perfectly.


// basic extend function
function extend(B, A){
function I(){};
I.prototype = A.prototype;
B.prototype = new I;
B.prototype.constructor = B;
B.prototype.parent = A;
};

// same stuff ...
function Person(name, age){
this.name = name;
this.age = age;
};
Person.prototype = (function(){
function toString(){
return this.name + " is " + this.age;
};
return {
constructor:Person,
toString:function(){
return this._(toString)();
},
_:function(callback){
var self = this;
return function(){
return callback.apply(self, arguments);
};
}
};
})();

// subclass
function Employee(company, name, age){
this.parent.call(this, name, age);
this.company = company;
};

extend(Employee, Person);

Employee.prototype.getFullDetails = function(){
// toString has been inherited from Person
// and it uses inside the private method
return this.toString() + " and works in " + this.company;
};

var other = new Employee("Mega Ltd", "Daniele", 26);
alert(
other.getFullDetails()
);

Finally, what we can do with this method, is to redefine them to allow us to overwrite private functions and/or use them without problems:

// above stuff + subclass
function Employee(company, name, age){
this.parent.call(this, name, age);
this.company = company;
};

extend(Employee, Person);

// extend prototype and return them
Employee.prototype = (function(proto){

function toString(){
return this.company;
};

proto.toString = function(){
return this.parent.prototype.toString.call(this) + " and works in " + this._(toString)();
};

proto._ = function(callback){
var self = this;
return function(){
return callback.apply(self, arguments);
};
};

return proto;
})(Employee.prototype);

alert(new Employee("Mega Ltd", "Daniele", 26));
// Daniele is 26 and works for Mega Ltd


That's it :)

Monday, March 24, 2008

My 5 cents about JavaScript Prototypal Inheritance

Few days ago I read an interesting post about Simple JavaScript Inheritance.
The most hilarious thing is that prototypal inheritance is truly simple, as John wrote, but there are still a lot of developers that do not probably understand perfectly them.

In this link you can find an "all in one" page about JavaScript prototypal inheritcance and classical emulation.

As I wrote at the end of that page, please do not hesitate to correct me if there is something wrong, or please ask me more details if there is something that is not so clear.

Sorry for my not perfect yet English, and have fun with JavaScript.

(happy easter too!)