My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label protected. Show all posts
Showing posts with label protected. 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.

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!)

Friday, March 21, 2008

How to inject protected methods in JavaScript - Part II

As a performances maniac, I've found another way to inject protected methods, or something similar, without unnecessary overload of each public method.

Of course, precedent way is definitively more clear, linear, but if you have a constructor.prototype with a lot of private methods, the overload process will be a wall in front of method execution speed.

Each time you will use a public method, you have to set, and unset, every protected method, and at the same time, as explained in my precedent post, you cannot send the object outside during public method execution, because it will expose every method, protected included.

This new proposal is based on a Function like strategy, applied to instances: apply, and call. Please have a look at this prototype function:

function prototype(constructor, public, protected){
// webreflection - mit style
if(protected){
public.apply = function(callback, arguments){
return (callback.charAt(0) === "_" ? protected : this)[callback].apply(this, arguments);
};
public.call = function(callback){
return this.apply.call(this, callback, Array.prototype.slice.call(arguments, 1));
};
};
public.constructor = constructor;
constructor.prototype = public;
return public;
};

A usage example should be this one:

function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);

The first sent object will be the prototype of MyMath constructor, while the second one will contain protected methods.

About performances


As you can see in the simple prototype function, there's no override and no overhead for both public and protected methods. This means that you can use a public method directly and without problems:

var num = new MyMath(3);
num.doStuff(); // direct, fast as regular prototype


About protected methods


These simply "does not exists" :)

var num = new MyMath(3);
num._doStuff(); // error

Protected methods are not directly accessible even from instance itself. This means that these methods are safe and not mutable, if used object is created in a private scope, or runtime as showed before.

How to use protected methods



var num = new MyMath(3);
alert(num.call("_doStuff")); // 6

Apply and call, in this case, are used with instance to call a method that, if contain an underscore as first prefix char, will be one from protected prototype, otherwise will be one of the public prototype. Sounds weird?

// full example
function MyMath(value){
this.value = value;
};
prototype(
MyMath,
{doStuff:function(){
return this.value * this.value;
}},
{_doStuff:function(){
return this.value + this.value;
}}
);

var num = new MyMath(3);
alert([
num.doStuff(), // 9
num.call("doStuff"), // 9
num.call("_doStuff") // 6
].join("\n"));

num._doStuff; // undefined


Why do I call them protected


If everyone can call a method, it does not make sense to call them protected.
But this time, the meaning is not the same of classical inheritance, but it is more close to the word itself: proteced.

The main goal is to have a not common or usual way to call methods, specially for libraries developers.
Every API could be based on public methods, while authors could choose to call a protected method when their need them.
This is basically a transparent layer between the developer and the final user: who will use num.call("doStuff") when you can do this: num.doStuff() ?

I know I am not so good to explain my ideas, so I hope someone will find this useful. Have a nice easter ;)