Friday, August 7, 2009

Javascript: Private Members through Closures

Back to the problem at hand: you need to create a variable that can only be accessed internally.
A closure seems to be a perfect fit because it allows you to create variables that are accessible
only to certain functions and are preserved in between those function calls. To create private
attributes, you define variables in the scope of your constructor function. These attributes will
be accessible to all functions defined within this scope, including privileged methods:
var Book = function(newIsbn, newTitle, newAuthor) { // implements Publication
// Private attributes.
var isbn, title, author;
// Private method.
function checkIsbn(isbn) {
...
}
// Privileged methods.
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');
isbn = newIsbn;
};
this.getTitle = function() {
return title;
};


this.setTitle = function(newTitle) {
title = newTitle || 'No title specified';
};
this.getAuthor = function() {
return author;
};
this.setAuthor = function(newAuthor) {
author = newAuthor || 'No author specified';
};
// Constructor code.
this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor);
};
// Public, non-privileged methods.
Book.prototype = {
display: function() {
...
}
};
So how is this different from the other patterns we’ve covered so far? In the other Book
examples, we always created and referred to the attributes using the this keyword. In this
example, we declared these variables using var. That means they will only exist within the Book
constructor. We also declare the checkIsbn function in the same way, making it a private method.
Any method that needs to access these variables and functions need only be declared
within Book. These are called privileged methods because they are public but have access to
private attributes and methods. The this keyword is used in front of these privileged functions
to make them publicly accessible. Because these methods are defined within the Book constructor’s
scope, they can access the private attributes. They are not referred to using this because
they aren’t public. All of the accessor and mutator methods have been changed to refer to the
attributes directly, without this.
Any public method that does not need direct access to private attributes can be declared
normally in the Book.prototype. An example of one of these methods is display; it doesn’t
need direct access to any of the private attributes because it can just call getIsbn or getTitle.
It’s a good idea to make a method privileged only if it needs direct access to the private members.
Having too many privileged methods can cause memory problems because new copies
of all privileged methods are created for each instance.
With this pattern, you can create objects that have true private attributes. It is impossible
for other programmers to create an instance of Book and directly access any of the data. You
can tightly control what gets set because they are forced to go through the mutator methods.
This pattern solves all of the problems with the other patterns, but it introduces a few drawbacks
of its own. In the fully exposed object pattern, all methods are created off of the prototype,
which means there is only one copy of each in memory, no matter how many instances you create.
In this pattern, you create a new copy of every private and privileged method each time a new

object is instantiated. This has the potential to use more memory than the other patterns, so it
should only be used when you require true private members. This pattern is also hard to subclass.
The new inherited class will not have access to any of the superclass’s private attributes or methods.
It is said that “inheritance breaks encapsulation” because in most languages, the subclass has
access to all of the private attributes and methods of the superclass. In JavaScript, this is not the
case. If you are creating a class that might be subclassed later, it is best to stick to one of the fully
exposed patterns.

Summary
1) To declare private variables dont use this keyword, instead use var with in the constructor.
2) The same applies to the private functions as well like checkIsbn() function above.
3) To declare public privileged functions [functions which are public and which can access private variables] use this keyword and define it with in the constructor like setIsbn(), getIsbn() api's above.
4) To declare public non-privileged functions [functions which are public and which cannot access private variables] use prototype to define.

Source:
Pro Javascript Design Patterns

No comments:

Post a Comment