Object-Oriented Programming with JavaScript, Part I: Inheritance(RT)
2006-12-09 02:52
435 查看
adapted from http://www.webreference.com/js/column79/
In this column we embark on a short series about Object-Oriented Programming (00P) with JavaScript. In Part I of this series, we will cover the fundamentals. We will show you how JavaScript fulfills one of the most important requirements from an object-oriented language: inheritance. The examples in this part will also demonstrate the other requirement: encapsulation. We'll leave the third requirement, polymorphism, to other parts of this series.
Although JavaScript is a scripting language, its support of object-oriented programming is quite impressive. Even though there are no classes and instances, there are objects, prototypes, and implicit inheritance. We will explain in detail how to emulate inheritance and how the superclass-subclass relationship is formed. Prototyping is the key to understanding the inheritance concept. We'll teach you how to establish prototyping, how to detect whether one object is a prototype of another object, and how JavaScript's model is different from Java's object-oriented programming. We'll also show you how to check several attributes of the object's properties.
The examples in this column are for JavaScript 1.1 and above, for both Internet Explorer and Netscape, unless noted otherwise.
In this column, you will learn:
How to characterize an object-oriented programming language
How to implement inheritance with functions
How to implement inheritance with prototyping
How to add properties after the object is created
How to probe inheritance in NS with __proto__
How to emulate instanceOf()
How to classify and print objects
How to query an object's properties
How to compare JavaScript and Java
Software reuse is another characteristic of OO design. One of the major ways to achieve software reuse is by inheritance. A class is a function that defines an object. A superclass is a class from which new classes, subclasses, are created. A subclass inherits all its methods and properties from its superclass. Practically, all subclasses are generated automatically, and hence the enormous savings. You don't have to define these subclasses one by one. Of course, you can override inherited methods and properties. In fact, there is no point to create a subclass which is a 100% duplication of its superclass, unless you override at least one property or one method.
Polymorphism is probably the most complicated component of the three must-haves. The essence of this concept is that every class should handle different data types. You shouldn't create different classes to handle different data types. The classic example is the drawing class. You should not write different classes to draw circles, rectangles, and ovals. It should be one class that is smart enough to call the proper method to operate on the appropriate shape.
Click here to invoke the following assignment and function that activate these objects:
Convince yourself that it is working correctly. The methods
Let's take another example. Here is the definition of
To activate the generation of
Notice the alert boxes. They show that the
Let's take the example from Page 3 and use the prototype assignment instead of these assignments inside the
Here is the new code:
Click here to invoke the following script that creates an instance of
Convince yourself that you get the same results as in Page 3:
Notice the three lines:
We define the function
Use the
It returns
Ken is in the
The object
is executed. The value of
Let's look at another example. In this example,
All alert boxes will yield a value of
The following code segment defines three classes:
You can probe the superclass of any object via its
When you ask for the
![](http://www.webreference.com/js/column79/8a.bmp)
The
The
Alert the object. You should get the string you passed to the constructor,
When you want to get a uniform feedback about an object's names and content, the best way is to ask for their string version. Use the object's methods of
the
The
where objName is the name of your object. In the following example we use the for loop to print ken's employee properties (
Try it. You will get two alert boxes: one for
Use the
An object's property may be enumerable. An enumerable property can assume only predefined values from a given list. The variable
It can assume one of three values only:
You can verify that indeed
The parameter of the method above should be numeric. Try it (IE 5.x and up, Netscape 6 and up).
How would the above example look in a class-based language? In Java, it is translated into something like that:
In this column we embark on a short series about Object-Oriented Programming (00P) with JavaScript. In Part I of this series, we will cover the fundamentals. We will show you how JavaScript fulfills one of the most important requirements from an object-oriented language: inheritance. The examples in this part will also demonstrate the other requirement: encapsulation. We'll leave the third requirement, polymorphism, to other parts of this series.
Although JavaScript is a scripting language, its support of object-oriented programming is quite impressive. Even though there are no classes and instances, there are objects, prototypes, and implicit inheritance. We will explain in detail how to emulate inheritance and how the superclass-subclass relationship is formed. Prototyping is the key to understanding the inheritance concept. We'll teach you how to establish prototyping, how to detect whether one object is a prototype of another object, and how JavaScript's model is different from Java's object-oriented programming. We'll also show you how to check several attributes of the object's properties.
The examples in this column are for JavaScript 1.1 and above, for both Internet Explorer and Netscape, unless noted otherwise.
In this column, you will learn:
How to characterize an object-oriented programming language
How to implement inheritance with functions
How to implement inheritance with prototyping
How to add properties after the object is created
How to probe inheritance in NS with __proto__
How to emulate instanceOf()
How to classify and print objects
How to query an object's properties
How to compare JavaScript and Java
Characterizing Object-Oriented Languages
Object-oriented design is based on three major principles: encapsulation, inheritance, and polymorphism. A programming language is said to support OO (Object-Oriented) design if it supports these three concepts in its syntax. Such a language should provide you with tools to easily define and use these paradigms. Encapsulation refers to the concept of making an object a "black box." When you use an object, you should not know its internal workings. You don't need to understand how an object works. An object should expose only the absolute necessary information needed to interface with it. It should give you a friendly interface to those limited set of methods and properties that the designer thought might be useful for other users. Encapsulation also means that an object includes everything it needs: both the data and the operations on it (methods). The encapsulation concept is very powerful because it allows an efficient division of labor in large software projects. Each team member can work on his or her object without interfacing too much with other members of the group. Overhead in development projects grows up exponentially with the number of interfaces between the group members. Encapsulation is a major contributor to OO design being a solution to the famous "Software Crisis."Software reuse is another characteristic of OO design. One of the major ways to achieve software reuse is by inheritance. A class is a function that defines an object. A superclass is a class from which new classes, subclasses, are created. A subclass inherits all its methods and properties from its superclass. Practically, all subclasses are generated automatically, and hence the enormous savings. You don't have to define these subclasses one by one. Of course, you can override inherited methods and properties. In fact, there is no point to create a subclass which is a 100% duplication of its superclass, unless you override at least one property or one method.
Polymorphism is probably the most complicated component of the three must-haves. The essence of this concept is that every class should handle different data types. You shouldn't create different classes to handle different data types. The classic example is the drawing class. You should not write different classes to draw circles, rectangles, and ovals. It should be one class that is smart enough to call the proper method to operate on the appropriate shape.
Inheritance through Functions
Although JavaScript does not support an explicit inheritance operator, you can implement inheritance in other ways. There are two different ways to establish a hierarchy of classes in JavaScript. The first method to create an object as a subclass of another object, is to call the superclass constructor function inside the subclass object definition. Let's look at the following example:function superClass() { this.bye = superBye; this.hello = superHello; } function subClass() { this.inheritFrom = superClass; this.inheritFrom(); this.bye = subBye; } function superHello() { return "Hello from superClass"; } function superBye() { return "Bye from superClass"; } function subBye() { return "Bye from subClass"; }
function printSub() { var newClass = new subClass(); alert(newClass.bye()); alert(newClass.hello()); }
bye()and
hello()are first defined in
superClass(). The method
bye()is being overridden in
subClass(). The first two lines of
subClass()does the original inheritance between the two classes. You first define the
inheritFrommethod, and then you call it:
this.inheritFrom = superClass; this.inheritFrom();
superclass()and
subclass()(different from the above
superClass()and
subClass()):
function superclass() { this.info = alert("Defining the Superclass"); } function subclass() { this.inheritFrom = superclass; this.inheritFrom(); this.info = alert("Overriding the Superclass"); }
subclass(), click here. This button calls the following function:
function createSubclass() { var newClass = new subclass(); }
infomethod is first defined in
superclass()and then is being overridden in
subclass().
Ineritance through Prototyping
The second and more robust method to establish a class hierarchy is by creating an object of the superclass and then assign it as aprototypeof the subclass object. Suppose our superclass is
superClassand our subclass is
subClass. The
prototypeassignment would look like this:
subClass.prototype = new superClass;
subClass()defintion:
this.inheritFrom = superClass; this.inheritFrom();
function superClass() { this.bye = superBye; this.hello = superHello; } function subClass() { this.bye = subBye; } subClass.prototype = new superClass; function superHello() { return "Hello from superClass"; } function superBye() { return "Bye from superClass"; } function subBye() { return "Bye from subClass"; }
subClass():
function printSub() { var newClass = new subClass(); alert(newClass.bye()); alert(newClass.hello()); }
bye()from
subClass()and
hello()from
superClass().
Adding Properties after the Object is Created
Inheritance by prototyping (Page 4) is better than inheriting by function (Page 3) because it supports dynamic inheritance. You can define superclass methods and properties after the constructor is done, and have the subclass object pick the new methods and properties, automatically. Here is an example that defines theblessyou()function after the objects are created:
function superClass() { this.bye = superBye; this.hello = superHello; } function subClass() { this.bye = subBye; } subClass.prototype = new superClass; function superHello() { return "Hello from superClass"; } function superBye() { return "Bye from superClass"; } function subBye() { return "Bye from subClass"; } var newClass = new subClass(); superClass.prototype.blessyou = superBlessyou; function superBlessyou() { return "Bless You from SuperClass"; } function printSub() { alert(newClass.bye()); alert(newClass.hello()); alert(newClass.blessyou()); }
superClass.prototype.blessyou = superBlessyou; function superBlessyou() { return "Bless You from superClass"; }
blessyou()and then print it from the
subclassobject:
function printSub() { var newClass = new subClass(); alert(newClass.bye()); alert(newClass.hello()); alert(newClass.blessyou()); }
isPrototypeOf()method to find out if
object2had
object1in its
prototypechain:
object1.prototype.isPrototypeOf(0bject2);
trueif
object2is an object and when
object1appears in the
prototypechain of
object2. Let's look at an example:
function Person() { this.name = "Rob Roberson"; this.age = 31; } function Employee() { this.dept = "HR"; this.manager = "John Johnson"; } Employee.prototype = new Person(); var Ken = new Employee();
prototypechain of
Employee,
Person, and
Object. Prove it to yourself by clicking on each class. They alert
Employee.prototype.isPrototypeOf(Ken),
Person.prototype.isPrototypeOf(Ken), and
Object.prototype.isPrototypeOf(Ken), respectively.
Probing for Inheritance in NS
In Netscape Navigator 4.x and Netscape 6, JavaScript stores the prototyping relationship in an internal property of the object,__proto__(two underscore characters at the front and two at the end.) Let's take an example:
function Shape() { this.borderWidth = 5; } function Square() { this.edge = 12; } Square.prototype = new Shape; myPicture = new Square; alert(myPicture.__proto__); alert(myPicture.borderWidth);
myPicturehas an internal property,
__proto__, which is set to
Shapewhen the statement:
Square.prototype = new Shape;
__proto__instructs JavaScript where to look for properties, when local definitions are not available. In the example above, the property
borderWidthis not defined within the object
Square. The browser looks for the value of
__proto__, which is
Shape, and then fetches the value of its
borderWidthproperty. Being an internal property, most browsers will return
undefinedwhen asked to alert
__proto__. Netscape 6, though, returns
[object Object]. Try it.
Let's look at another example. In this example,
UniversityAvenueinherits from Street, which inherits from
City, which inherits from
State:
function State() { } function City() { } City.prototype = new State; function Street() { } Street.prototype = new City; var UniversityAvenue = new Street(); function tryIt() { alert(UniversityAvenue.__proto__== Street.prototype); alert(UniversityAvenue.__proto__.__proto__== City.prototype); alert(UniversityAvenue.__proto__.__proto__.__proto__ == State.prototype); alert(UniversityAvenue.__proto__.__proto__.__proto__. __proto__== Object.prototype); alert(UniversityAvenue.__proto__.__proto__.__proto__. __proto__.__proto__== null); }
truein Netscape Navigator 4.x and Netscape 6. Try it.
__proto__is not supported by Internet Explorer.
Emulating instanceOf()
Sometimes, you need to find out if a certain object is an instance of a given class (constructor()function). In other languages, this operation is called
instanceOf(). JavaScript does not support the
instanceOf()method, but we can write one ourselves, using the internal
__proto__(two underscores on each side) property. The algorithm is based on searching the object's constructor along the inheritance chain, using
__proto__:
function instanceOf(object, constructorFunction) { while (object != null) { if (object == constructorFunction.prototype) {return true} object = object.__proto__; } return false; }
State,
City, and
Street. The
Street's
prototypeis
City, and the
City's
prototypeis
State. If
UniversityAvenueis an instance of
Street, it is also an instance of
Cityand
State. This demo (Netscape only) proves it by showing all the above
instanceOf()relationships to be true:
function instanceOf(object, constructorFunction) { while (object != null) { if (object == constructorFunction.prototype) {return true} object = object.__proto__; } return false; }
function State() {
}
function City() {
}
City.prototype = new State;
function Street() {
}
Street.prototype = new City;
var UniversityAvenue = new Street();
function demo() {
alert("instanceOf(UniversityAvenue, Street) is " +
instanceOf(UniversityAvenue, Street));
alert("instanceOf(UniversityAvenue, City) is " +
instanceOf(UniversityAvenue, City));
alert("instanceOf(UniversityAvenue, State) is " +
instanceOf(UniversityAvenue, State));
}
You can probe the superclass of any object via its
constructorproperty. This property returns the function by which the object was created with the new operator. All objects (both native and user-defined) inherit from the
Objectobject. Since the
Objectobject supports the
constructorproperty, all objects supports it as well. Let's look at the
Employeeobject:
function Employee() { this.dept = "HR"; this.manager = "John Johnson"; } function printProp() { var Ken = new Employee(); alert(Ken.constructor); }
constructorproperty, you should get a listing of the
Employeefunction:
![](http://www.webreference.com/js/column79/8a.bmp)
Classifying and Printing Objects
JavaScript supports three types of objects: native, host, and user-defined. Native objects are objects supplied by the JavaScript language.Object,
Math, and
Numberare examples of native objects. Native object names start with a capital letter, and they are case-sensitive. To find the value of the mathematical constant
PI, type
Math.PI. If you try
math.PI, you'll get an error message. Host objects are provided by the browser for the purpose of interaction with the loaded document. Examples for host objects are:
document,
window, and
frames. Host object names start with a lower-case letter. You can print on the screen the value of
PIby
document.write(Math.PI). Try
Document.write()and you'll get an error message. You define user-defined objects. You name the objects and you implement them. Your objects can start with either a lower-case letter or an upper-case letter, but they are case-sensitive. Here is an example that gives an error message because of case mismatch (try it):
function employee() { this.dept = "HR"; this.manager = "John Johnson"; } function printProp() { var ken = new Employee(); for (property in ken) { alert(property); } }
Objectobject is the base object for all native and user-defined objects. All objects inherit from this superclass. You can create an
Objectobject as well:
var myObject = new Object();
Objectobject has a dozen of properties and methods. Examples are
constructor,
toString(), and
valueOf(). The object
myObjectabove sports these properties. Alert the object. You should get
[object Object]. You can pass a string to the
Objectconstructor:
var myObject = new Object("foo");
"foo". The native objects sports the same properties, because they inherit from the
Objectclass. Probe the constructor property of the
Mathobject,
Math.constructor. The answer you should get is that the
Objectobject is the constructor of the
Mathobject.
When you want to get a uniform feedback about an object's names and content, the best way is to ask for their string version. Use the object's methods of
toString(),
toLocaleString(), and
valueOf(). When the object consists of a number, like:
var myNum = new Number(35);
toString(),
toLocaleString(), and
valueOf()methods return the string
"35". When the object is user-defined, they return
[object Object]. Try it for the following
Employeeobject:
function Employee() { this.dept = "HR"; this.manager = "John Johnson"; } function printProp3() { var Ken = new Employee(); alert(Ken.toString()); }
toLocaleString()prints its object according to your definitions in the Control Panel's Regional Settings file.
Querying an Object's Properties
JavaScript provides you with a way to loop over an object's properties. You can use this loop technique to find out the names of an object's properties. The looping is done with aforloop:
for (property in objName)
deptand
manager):
function employee() { this.dept = "HR"; this.manager = "John Johnson"; } function printProp() { var ken = new employee(); for (property in ken) { alert(property); } }
deptand one for
manager.
Use the
hasOwnProperty()method to find out if an object has a certain property you are interested in. The
hasOwnProperty()is a method of the
Objectobject, and thus all objects inherit it (all objects are subclasses of the
Objectobject). The following code checks if the object
Kenof the
Employeesubclass has a
manager. Try it (IE 5.x and up, Netscape 6 and up), it should give
true:
function printProp2() { var Ken = new Employee(); alert(Ken.hasOwnProperty("manager")); }
ais enumerable:
a = new Array("jan", "feb", "march");
"jan",
"feb", or
"march". The following script defines the object Employee1, where the property
monthis enumerable:
function Employee1() { this.dept = "HR"; this.manager = "John Johnson"; this.month = new Array("jan", "feb", "mar"); } var Ken = new Employee1();
monthis enumerable by:
Ken.month.propertyIsEnumerable(0);
Comparing JavaScript and Java
As opposed to Java, which is a class-based language, JavaScript is a prototype-based language. This difference is reflected everywhere. The term instance, for example, has a specific meaning in class-based languages. An instance is an individual member of a class. It is an implementation of the class definition. In JavaScript, the term "instance" does not have this technical meaning, because there is no such difference between classes and instances. However, instance can be used informally to mean an object created using a particular construction function. In the following example:function superClass() { this.bye = superBye; this.hello = superHello; } function subClass() { this.bye = subBye; } subClass.prototype = new superClass; function superHello() { return "Hello from superClass"; } function superBye() { return "Bye from superClass"; } function subBye() { return "Bye from subClass"; } var newClass = new subClass();
newClassis an instance of
subClass(). It was created according to
subClass()'s constructor function.
How would the above example look in a class-based language? In Java, it is translated into something like that:
public class superClass { public superClass () { this.bye = superBye; this.hello = superHello; } } public class subClass extends superClass { public subClass () { this.bye = subBye; } }A Final Word
In this column we presented Part I of our series about object-oriented programming with JavaScript. We focused on the inheritance principle and how it is emulated by the language. We showed you two different ways to implement inheritance, and delved into the prototyping method. We demonstrated how to check for a superclass/subclass relationship between objects. We explained how to list an object's properties, and how to verify that indeed a certain property exists. We rounded up this column by a comparison of JavaScript and Java as object-oriented languages. In this column, you have learned: How to characterize an object-oriented programming language How to implement inheritance with functions How to implement inheritance with prototyping How to add properties and methods after the object is created How to probe inheritance in NS with __proto__ How to check for prototyping How to classify and print objects How to query an object's properties How to compare JavaScript and Java
相关文章推荐
- JavaScript and Object Oriented Programming (OOP)
- 《Object-Oriented Programming With ANSI-C》之第四章(继承——代码重用和改进)
- 《Object-Oriented Programming With ANSI-C》之第二章(动态链接和泛函数)
- Object Oriented Programming in JavaScript 在Javascript中使用面向对象的编程
- Object-Oriented Programming with Objective-C
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)
- Beginning Object-Oriented Programming with VB 2005: From Novice to Professional
- javascript object oriented programming (一)
- 《Object-Oriented Programming With ANSI-C》之序言
- javascript object oriented programming (二)
- LingOOP: Object-Oriented Programming with Lingo
- 《Object-Oriented Programming With ANSI-C》之第一章(抽象数据类型—信息隐藏)
- JavaScript and Object Oriented Programming (OOP)
- javascript object oriented programming (三)
- 《Object-Oriented Programming With ANSI-C》之第三章(编程的悟性——算术表达式)
- “What's wrong with Object-Oriented Programming and Functional Programming”
- POLYMORPHISM with C++ - OBJECT ORIENTED PROGRAMMING
- Object-Oriented Programming with PHP5
- Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Jav
- 《Object-Oriented Programming With ANSI-C》 C++对象模型的经典之作