Encapsulate Your JavaScript: Keep Private Methods Private

ne of the questions I hear asked most frequently is: Is JavaScript a true object-oriented language? There’s no easy answer for the question. It certainly helps beginning JavaScript programmers to think of writing JavaScript in terms of objects, but that doesn’t answer the question.



Problem: Is JavaScript a true, object-oriented language? If so, what OOP features does it support, and how can you use them?



Solution: JavaScript 1.2 supports some object-oriented principles such as encapsulation and prototype-based inheritance. You’ll see how to create objects with private properties and methods.Is JavaScript Object-Oriented?
When considering object-oriented programming languages, it’s convenient to exclude JavaScript from the set of modern, object-oriented languages. JavaScript does, however, make use of some object-oriented principles. In this article, I’ll show you how JavaScript handles inheritance and encapsulation. Because I have a Java background, and because Java is an object-oriented language, I’ll be making comparisons between JavaScript and Java throughout this article.

One reason JavaScript is not considered an object-oriented language is that, unlike Java, JavaScript is not strongly typed. JavaScript, variables do not possess data types (which has nothing to do with how hard it is to type the code!). Rather, a variable’s data type depends on the value you assign to a variable. Further, you are free to change the type by simply assigning a different type of data to the variable or treating the data in a different way. For example in JavaScript you can write:

   var myVar = “a string”;   myVar = 4;   alert(“myVar = ” + myVar);
The code initially creates the myVar variable as a string but it becomes an integer by assigning 4 to it on the second line. Then, when the script displays the value, it casts the integer variable myVar back into a string, this time containing a string representation of the integer value. This is perfectly legal in JavaScript. In fact, it’s one of the reasons why JavaScript is easier to write than Java?you don’t have to worry about what type of data you are dealing with. In Java, the compiler would raise an error for either of the preceding lines of code. The equivalent Java would be:

   String myString = “a string”;   int myInt = 4;   System.out.println(“myInt = ” + myInt.toString()); 
In Java you must declare the data type with the variable and, in this case, you’d need two variables?one for each data type. If you want to change the data type of a variable in Java, you would create a new variable of the correct data type and then cast the variable from one type to the other. But sometimes casting just isn’t possible.

Another reason JavaScript is easily dismissed as an OOP language is that it doesn’t use class-based inheritance. In Java, you define objects in a logical hierarchy with more abstract objects at the top of the hierarchy and more concrete objects at the bottom. This top-down design makes it easy to say something like: “A four-wheeled vehicle is an object and a car is a specific kind of four-wheel vehicle.” That way, cars inherit all of the things that come with four-wheel vehicles and also add additional information specific to cars. Class-based inheritance is a powerful mechanism when you consider that the hierarchy can have many levels, each of which is added to all objects further down. In essence, you design objects in Java by determining how they are different from other, existing objects.

   function personName() {     this.firstname=null;     this.lastname=null;   }
JavaScript doesn’t support class-based inheritance, but it does support prototype-based inheritance. Prototype-based inheritance differs from class-based inheritance in that properties and methods are inherited from a constructor only, not from a class higher up in the hierarchy. All object constructors in JavaScript create objects whose properties and methods are inherited from the properties and methods of the prototype.Building JavaScript Objects
Suppose you wanted to create an object in JavaScript modeled after a person. This person object will contain two properties (for now)?a last name and a first name. First, design the prototype function:

   function person() {      }
Next, add the parameters used to initialize the properties:

   function person(first,last){      }
Finally, assign the parameters to property placeholders within the prototype:

   function person(first,last) {      this.firstName = first;      this.lastName = last;   }
Notice that the properties, firstName and lastName, are nested within the prototype. The this keyword seems to associate them with the object but, as you’ll see a little later, the this keyword also makes the properties publicly available to outside routines. In fact, the nesting of the properties alone makes them local to the object.

Later in your code, you can create as many person objects as you’d like, each of which automatically has firstName and lastName properties:

   var tDuffy = new person(“Tom”,”Duffy”);
So, if JavaScript does indeed use inheritance, does it also make use of other object-oriented principles? The answer is?although it’s under-used, yes; JavaScript also handles encapsulation.Encapsulation
The concept of encapsulation means that an object’s data members should remain private to the object and manipulated through publicly exposed methods. In other words, programs should not have the ability to change the properties of objects directly. In traditional JavaScript, you are free to modify the values of an object’s properties simply through assignment. For example, you can modify a person object’s data fields directly, which breaks the concept of encapsulation:

   tDuffy.firstName = “Kelli”;
Encapsulation states that firstName should not be available directly for manipulation and should be manipulated through a public method:

   tDuffy.setFirstName(“Kelli”);
Most JavaScripters find the creation of private data members (variables and methods) foreign; however, it’s rather easy to implement. A typical Java class contains a constructor, private member variables, and methods, and so does a JavaScript object. You need two techniques to accomplish encapsulation in JavaScript: nested functions and omission of the this keyword in object constructors. Be aware, though, that nested functions are part of the JavaScript 1.2 release, so they won’t be available in downlevel browsers.Build the Example
Open your favorite text editor, enter or download the code in Listing 1, and save the file as myObject.js:

This code looks slightly different than most JavaScript. Notice that all the code exists within the function definition?in other words, the member functions are nested within the myObject() function. The myObject() function is the constructor for objects of type myObject. Nothing new there. The next two lines declare two member variables, prop1 and prop2, and initialize them. Notice that the function omits the this keyword and uses the var keyword instead. Omitting the this keyword makes the variables private to the object. The var keyword makes the property local (each object instance gets its own copy of the variable). Calls to internal methods then assign the passed argument values to the properties (see the SideBar Cross-Browser Issues with the Sample Code).

The next part of the code is a list of method pointers defined with the this keyword. The method pointers make the methods public. Each method pointer points to a getter or setter method that lets you retrieve and set the values of the private data member values. In essence, they let the object control how the values change internally. Although most of the methods shown only manipulate properties, you’re can include non-property methods. For example, the getProps() method returns the list of property getters and setters.. Note that any method included inside the constructor that does not possess a method pointer is a private method. A private method can be used only by the object itself?it cannot be called from outside the object.

After declaring the method pointers, the myObject() function defines a set of nested functions. Only instances of myObject will have access to these private functions. Consider the following:

   var myObj = new myObject(“Tom”,”Duffy”);   alert(getProp1());
The second line throws an error indicating that getprop1() is undefined. The correct call looks something like this:

   alert(myObj.getprop1());
That code will display “Tom”?as it should.

Finally, note that the private function called privateMethod() is invisible outside of the myObject function. By omitting the method pointer to privateMethod() and nesting it within the myObject() function, neither a calling script nor an object instance can make use of privateMethod(). It exists solely to provide some mechanism to another public method inside the object?in this case the trivial testPrivateMethod() function.A Test Run
Open a new document in your text editor, add the following code, and save it as oopTest.htm in the same folder as myObject.js:

            OOP JavaScript Test                  

Property 1:

Property 2:

Change Property 1 to:

Change Property 2 to:

Then open the file in a JavaScript 1.2 capable browser (I test with IE 5.0, Netscape 4.7, and Netscape 6.0). Start by entering values in the first two text fields and initialize the object. Then modify the values in the next two fields to change the properties. Finally, test the private method. You should see three alert boxes. The first two alerts display the values you entered. The third alert displays the predefined properties set in the private method.

As you can see, JavaScript can be more object-oriented than most people think. The ECMAScript specification, to which JavaScript must adhere, lists future reserved words such as class, super, import, and extends. These reserved words are all used by Java for class-based inheritance. This indicates to me that JavaScript will migrate even closer to Java in the not-too-distant future.

The chief benefit of using object-oriented principles is code reuse. In fact, the encapsulation process detailed above closely mirrors Java’s component architecture?the JavaBeans specification. By encapsulating the functionality of an object, you or any other developer can simply forget about the implementation and make use of the functionality in any future project.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: