71.141.96.194 at 07:19, 10 September 2010 - 2010-09-10 07:19:59

←Older revision Revision as of 07:19, 10 September 2010
Line 34: Line 34:
}
}
-
$(document).ready(function(){
+
$(function(){
var api = create($("a"), $("#counter"));
var api = create($("a"), $("#counter"));

JaroslavTulach: New page: Can you hide anything in a dynamic language like Javascript? If there are no access modifiers to make something ''private'' and when everyone is allowed to... - 2009-08-05 04:31:22

New page: Can you hide anything in a dynamic language like Javascript? If there are no access modifiers to make something ''private'' and when everyone is allowed to...

New page

Can you hide anything in a dynamic language like [[Javascript]]? If there are no [[ClarityOfAccessModifiers|access modifiers]] to make something ''private'' and when everyone is allowed to dynamically add new fields, functions to any object or even remove them, then it is really hard to keep something private.

Still, as a framework writer you want to separate an [[API]] from an implementation. You need to make it hard (if not impossible) for your users to cheat and bypass your [[API]]. Documenting what is ''public'' and what is not is not enough. Users resort to documentation only when completely lost. Until then they act [[cluelessness|cluelessly]] and try to make things work first and only later (if ever) think of what they did. The users need to face a wall when they try to use an implementation detail (unless you want to get stuck as me with [[APILessAPI|one mediawiki version]]). Can that be done in [[Javascript]]?

=== Scope instead of private ===

The ''private'' modifier is missing in [[Javascript]]. No fields can be guarded against modification. Where can one hide own state? Inside a method body! Looks like there is no way to inspect a body of a '''function''' and as functions can be nested (and see the other functions local variables) one can use following trick:

<source lang="javascript">
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function create(what,counter) {
var impl = {
};
impl.what = what;
impl.cnt = 0;
impl.counter = counter;

var api = {
};
api.toggle = function() {
if (impl.cnt++ % 2 == 0) {
$(impl.what).hide("slow");
} else {
$(impl.what).show("fast");
}
$(impl.counter).text(impl.cnt);
};
return api;
}

$(document).ready(function(){
var api = create($("a"), $("#counter"));

$("a").click(function(event){
api.toggle();
event.preventDefault();
api.toggle();
});
});

</script>
</head>
<body>
<a href="http://apidesign.org/">Toggle on and off</a><br>Toggle count: <span id="counter">0</span>
</body>
</html>
</source>

The [[API]] consist of one [[factory]] method (''create'') which returns an object with ''toggle'' method (there could be more method of course). This object keeps its internal state (reference to two document elements and a counter) in separate ''impl'' object which cannot be referenced by users holding just the [[API]] object. Looks like we successfully replaced missing access modifiers with a visibility scope.


=== Contest ===

I know all tricks a [[Java]] [[API]] users can do, but I do not claim to be a [[Javascript]] expert. Maybe there is a way to get on hand of the internals. Thus, let's try a contest: Who ever manages to write a [[Javascript]] code to:

<source lang="javascript">
var api = create($("a"),$("#counter");
api.toggle();
// TBD: somehow clean the internal counter
api.toggle();
// now the internal counter shall be 1 and not 2
</source>

will be a winner and gets a special section in another [[API Design Tips]] podcast.

<comments/>

[[Category:APIDesignPatterns]] [[Category:APIDesignPatterns:Encapsulation]]