JavaScript Object-Oriented Programming and Type Reflection Extensions The .NET Framework comes with the following two important programming capabilities: ❑ Fully fledged typing and typ
Trang 1JavaScript Object-Oriented Programming and Type Reflection Extensions The NET Framework comes with the following two important programming capabilities:
❑ Fully fledged typing and type reflection capabilities, allowing you to perform runtime-type inspections, discoveries, invocations, instantiations, and the like
❑ Fully fledged object-oriented capabilities, allowing you to take full advantage of all the well-known benefits of object-oriented programming (OOP) such as classes, interfaces, inheritance, and the like
Because the main goal of the ASP.NET AJAX client-side framework is to emulate the ASP.NET and NET Frameworks as much as possible, the ASP.NET AJAX client-side framework comes with a set
of extensions — known as the ASP.NET AJAX OOP and type reflection extensions — that add like OOP and type reflection capabilities to JavaScript as much as possible
You’ve already seen some reflection capabilities in Chapter 2 where the ASP.NET AJAX client-side Framework extends the JavaScript Object type to add support for the getType and getTypeName methods
The NET Framework comes with an important class named Type that provides most of the tion capabilities of the Framework Following the same pattern, the ASP.NET AJAX client-side framework introduces a type named Type , which provides both OOP and type reflection capabili-ties, which I’ll discuss in this chapter
First, I’ll examine the JavaScript technologies that the ASP.NET AJAX OOP and type reflection extensions use under the hood to extend JavaScript to add OOP and type reflection support This examination will put you in a much better position to understand and to use the ASP.NET AJAX client-side framework
Trang 2JavaScript Functions
Every JavaScript function is an instance of a JavaScript type named Function and supports the
follow-ing properties:
❑ arguments : This property contains the parameters of a JavaScript function, which also includes
the parameters that the original definition of the function does not contain You can use this
property to access the parameters of a function within the body of the function As the following
code shows, you can even define a function without any parameters and use the arguments
property to access the parameters However, this is not a recommended practice
❑ constructor : The constructor property references the function or constructor that was invoked
to create an object For example, if you run the following code, the alert will show function
Function () { [ native code ] } :
❑ prototype : The prototype property allows you to extend the functionality of a type to add
sup-port for new instance properties and methods JavaScript guarantees that all instances of the type
will automatically inherit these new properties and methods As you’ll see later, the ASP.NET AJAX
client-side framework makes extensive use of this property to add OOP support to JavaScript
Trang 3Every JavaScript function also supports two methods, call and apply , that you can use to invoke a function object Using these methods to invoke a function may sound redundant because you can invoke
a function by simply naming it For example, you can invoke the MyFunction JavaScript function defined in the previous code fragment by simply calling MyFunction(); Why would anyone then call
MyFunction.call() to invoke the function when you can directly call the function itself?
The call and apply methods enable you to specify the this value used inside a JavaScript function As you can see, JavaScript enables you to specify not only the parameters passed into a JavaScript function but also the this value As such, the first parameter of the call and apply methods references a
JavaScript object, which is used to set this value Note that this JavaScript object does note have to own the JavaScript function on which the call or apply method is invoked As you’ll see later, the ASP.NET AJAX client-side framework uses this feature when it’s adding OOP support to JavaScript
Based on the fact that both the call and apply methods do the same thing — that is, invoke their ciated method — you may be wondering why there are two methods The main difference between these two methods is in how the parameters of their associated JavaScript functions are passed into these two methods If your parameters are already loaded into an array, you can call the apply method and pass the array directly to this method Otherwise, you can call the call method, passing the parameters as a list of comma-separated items
JavaScript Classes
JavaScript is inherently an object-based programming language, not an object-oriented programming
language As such, it has limited OOP support, which is discussed in this section There is no JavaScript keyword equivalent to the C# or VB.NET class keyword The constructor of a JavaScript class also defines the class itself Listing 4-1 presents an example of a JavaScript class named Employee Listing 4-1: A JavaScript Class
<%@ Page Language=”C#” %>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Untitled Page</title>
<script language=”JavaScript” type=”text/javascript”>
function Employee (firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
Employee.prototype = {
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
}
(continued)
Trang 4As mentioned earlier, the ASP.NET AJAX client-side framework introduces a new type or class named
Type Let’s take a look under the hood to see what the Type class is:
window.Type = Function;
As you can see, Type is basically a new alias for the Function class This aliasing is done because
“Type” makes more sense in the context of the NET Framework Keep in mind that the main goal of
ASP.NET AJAX is to make the client-side framework act like the NET Framework as much as possible
Aliasing Function to Type is just a simple first step toward this goal The next step is to extend the Type
(formerly known as Function ) class to add support for new methods and properties that will help make
the client-side programming more like server-side NET programming
As discussed previously, Type (or Function ) features a property named prototype The JavaScript
engine guarantees that every instance of Type automatically inherits every method and property
assigned to the prototype property This means that every JavaScript function will automatically inherit
or pick up every method and property assigned to the prototype property of the Type or Function
class Because the constructor of every JavaScript class, including your own custom classes such as
Employee , is nothing but a JavaScript function, this also means that every JavaScript class, including
your own custom classes, will automatically inherit every method and property assigned to the
prototype property of the Type or Function class
Next, you’ll learn how the ASP.NET AJAX client-side framework takes full advantage of this powerful
feature of JavaScript to extend Type to add support for common OOP features such as namespaces,
classes, inheritance, interfaces, and the like Each of the following sections covers one of the new
meth-ods or properties that the ASP.NET AJAX client-side framework has added to Type (or Function ) Each
section consists of three parts The first part describes what the method does The second part presents
an example where the method is used The third part looks under the hood to show you how the method
is implemented internally Knowing the internals of these methods and properties will put you in a
much better position to understand and to extend the ASP.NET AJAX client-side framework
Trang 5register Class
The ASP.NET AJAX client-side framework extends the functionality of Type to add support for a new method named registerClass As the name implies, this method registers a specified class with the ASP.NET AJAX client-side framework
To add a new class to the ASP.NET AJAX client-side framework, you first need to implement the class For example, the following code implements a class named Employee :
Employee = function (firstName, lastName) {
this_firstName = firstName;
this_lastName = lastName;
}
Employee.prototype = {
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
}
Then, call the registerClass function of the Employee class to register your new class with the ASP.NET AJAX client-side framework, as follows:
Employee.registerClass(“Employee”);
Listing 4-2 presents a page that defines, registers, and uses the new Employee class
Listing 4-2: Registering the Employee Class
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
Employee = function (firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
(continued)
Trang 6Listing 4-2 (continued)
Employee.prototype =
{
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
However, as Listing 4-2 shows, the Employee class does not contain this method To understand how
this is possible, you need to look at the internal implementation of the registerClass method
shown in Listing 4-3 As this code listing shows, the registerClass is assigned to the prototype
property of the Type or Function class As discussed before, every JavaScript class, including your
own custom classes, automatically inherits any method or property assigned to the prototype
Note that Listing 4-3 presents a portion of the internal implementation of the registerClass function
You’ll see the rest of the implementation of this function in the following sections Also notice that
Trang 74 It uses the name of the class as an index to store the current class in the _classes object:
window. classes[c.toUpperCase()] = this;
This means that the ASP.NET AJAX client-side framework maintains an internal object that contains all the classes registered with the framework This allows you to perform runtime class reflection queries, similar to NET class reflection queries
This also means that every class registered with the ASP.NET AJAX client-side framework maintains metadata information, such as the type name, in its internal fields, such as _typeName This enables you
to perform runtime object reflections similar to NET object reflections on registered classes You’ll see an example of this reflection in the next section
get Name
The getName method returns the name of the specified type, as shown in the following example This is
a simple example of the reflection capabilities of the ASP.NET AJAX client-side framework
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
(continued)
Trang 8Employee = function (firstName, lastName)
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
Once again, note that the getName method is called directly on the Employee class, implying that this
class contains this method As the following code shows, this is possible because the getName method is
assigned to the prototype property of Type :
The isClass method is a static method of the Type class, which means that you must call this method
directly on the Type itself This method returns a Boolean value that specifies whether the parameter
passed into it is a class For example, the call into the isClass function in the boldfaced portion of the
following code listing returns true, because Employee is registered as a class:
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
Trang 9Employee = function (firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
Employee.prototype = {
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
As the following code shows, the isClass method is a static method because it’s not defined on the
prototype property Note that this method simply returns the value of the _class private field cussed in Listing 4-3 The isClass method is yet another example of the ASP.NET AJAX client-side framework’s type reflection capabilities
dis-Type.isClass = function(a){
if(typeof a === “undefined” || a === null) return false;
JavaScript Because this method is static, you must call it directly on the Type itself Here is an example:
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
Type.registerNamespace(“MyNamespace”);
(continued)
Trang 10MyNamespace.Employee = function (firstName, lastName)
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
Then it defines a class named Employee that belongs to this namespace:
MyNamespace.Employee = function (firstName, lastName)
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
}
Finally, it registers the class with the ASP.NET AJAX client-side framework:
MyNamespace.Employee.registerClass(“MyNamespace.Employee”);
Note that the namespace of a class is part of the name of the class
Listing 4-4 presents the internal implementation of the registerNamespace method As the first
line of code shows, the ASP.NET AJAX client-side framework adds a new global array named
_rootNamespaces to the window object As you’ll see shortly, the registerNamespace method
adds the global namespace being registered to this global array In other words, this global array
contains all the global namespaces registered with the ASP.NET AJAX client-side framework
Trang 11Listing 4-4: The Internal Implementation of the register Namespace Function
window. rootNamespaces = [];
Type.registerNamespace = function(f){
var d = window, c = f.split(“.”);
for(var b = 0; b < c.length; b ++ ) {
var e = c[b], a = d[e];
if( ! a) {
a = d[e] = {};
if(b === 0) window. rootNamespaces[window. rootNamespaces.length] = a;
a. namespace = true;
a. typeName = c.slice(0, b + 1).join(“.”);
a.getName = function() {
Now, I’ll walk through the code shown in Listing 4-4 to examine how the ASP.NET AJAX client-side framework manages to add a namespace capability to JavaScript In general, there are two types of namespaces: global and local A local namespace is one that is a subset of another namespace A global namespace is a namespace that does not belong to any other namespace For example, you could have a global namespace named Department , which in turn may contain one or more local namespaces, such
as Section , as in Department.Section The Section sub-namespace in turn may contain one or more namespaces, such as SubSection , as in Department.Section.SubSection
As Listing 4-4 shows, the ASP.NET AJAX client-side framework maintains all global namespaces in the
_rootNamespaces array In the following section of the listing, the object that represents a namespace features a Boolean field named _namespace that specifies that this object is a namespace, a string field named _typeName that contains the fully qualified name of the namespace such as Department Section , and a getter method named getName that returns the fully qualified name of the namespace:
a. namespace = true;
a. typeName = c.slice(0, b + 1).join(“.”);
a.getName = function() {
return this. typeName }
The object that represents a namespace, such as Department , also acts as a container (hash) for the objects that represent its sub-namespaces, such as Section
Trang 12is Namespace
The isNamespace method is a static method of the Type class This method returns a Boolean value that
specifies whether the specified object is a namespace For example, the call into the isNamespace function in
the boldfaced portion of the following code returns true because MyNamespace is registered as a namespace:
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}
Listing 4-5 presents the internal implementation of the isNamespace method This method simply
returns the value of the _namespace field of the object As you may recall from Listing 4-4 , the
registerNamespace method sets the _namespace field of the object that represents the namespace to
true to signal that the object is a namespace This is yet another example of the type reflection
capabili-ties of the ASP.NET AJAX client-side framework
Listing 4 -5: The Internal Implementation of is Namespace
Trang 13<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
throw Error.notImplemented();
};
function Department$IEmployee$set_employeeID () {
throw Error.notImplemented();
};
Department.IEmployee.prototype = {
get_employeeID : Department$IEmployee$get_employeeID, set_employeeID: Department$IEmployee$set_employeeID }
get_firstName : function () {return this._firstName;},
(continued)
Trang 14Listing 4-6 (continued)
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;},
get_employeeID : function () {return this._employeeID;},
set_employeeID : function (value) {this._employeeID = value;}
Obviously, you have to first define the interface before you can register it Defining an interface is pretty
much like defining a class, with one big difference: The constructors, methods, and properties raise
exceptions
Next, you need to register the interface, as follows:
Department.IEmployee.registerInterface(“Department.IEmployee”);
Listing 4-6 shows you how to write a class that implements the interface First you need to define the
class As the boldfaced portion of the following code shows, the Employee class implements the
get_employeeID and set_employeeID methods of the IEmployee interface:
Department.Employee = function (firstName, lastName)
get_firstName : function () {return this._firstName;},
set_firstName : function (value) {this._firstName = value;},
get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;},
get_employeeID : function () {return this._employeeID;},
set_employeeID : function (value) {this._employeeID = value;}
}
Next, you need to register your class, like this:
Department.Employee.registerClass(“Department.Employee”, null, Department IEmployee);
Note that the registerClass method takes a third parameter, which references the interface Passing
this parameter into the registerClass tells the ASP.NET AJAX client-side framework that the class
Trang 15being registered implements the specified interface, as you can see here:
Department.Employee.prototype.getEmployeeID = function () {
Listing 4 -7: The Internal Implementation of registerInterface
Type.prototype.registerInterface = function(a){
parame-in later sections of this chapter The third optional parameter of registerClass contains the interfaces that the class being registered implements The highlighted portion of Listing 4-8 shows the internal implementation of the registerClass method that handles the third parameter
Listing 4 -8: The Portion of the Internal Implementation of the register Class Function
Type.prototype.registerClass = function(c, b, d){
this.prototype.constructor = this;
this. typeName = c;
this. class = true;
if(!window. classes) window. classes = [];
window. classes[c.toUpperCase()] = this;
if(d) { this. interfaces = [];
for(var a = 2; a < arguments.length; a ++ )
(continued)
Trang 16The highlighted portion of Listing 4-8 takes these steps:
1 It defines and instantiates a new array field named _interfaces As you’ll see shortly, the
registerClass method uses this array field as a stack, which JavaScript implements as an array
this. interfaces = [];
2 It iterates through the interfaces that the third parameter of registerClass contains and
pushes each enumerated interface onto the top of the stack:
var e = arguments[a];
this. interfaces.push(e)
As these steps show, each class maintains an internal stack that contains the interfaces that the class
implements As you’ll see in the next sections, this internal stack enables you to perform NET-like
interface-related reflections on a given type or class This stack is an example of NET-like metadata
get Interfaces
The getInterfaces method enables you to query a type for all the interfaces that the type and its
ancestor types implement The boldfaced portion of the following code first calls the getInterfaces
function on the Department.Employee type to return an array that contains all the interfaces that
this type and its ancestor types implement, and then iterates through these interfaces and displays
Trang 17<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
throw Error.notImplemented();
};
function Department$IEmployee$set_employeeID () {
throw Error.notImplemented();
};
Department.IEmployee.prototype = {
get_employeeID : Department$IEmployee$get_employeeID, set_employeeID: Department$IEmployee$set_employeeID }
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}, get_employeeID : function () {return this._employeeID;}, set_employeeID : function (value) {this._employeeID = value;}
}
Department.Employee.registerClass(“Department.Employee”, null, Department.IEmployee);
var interfaces = Department.Employee.getInterfaces();
for (var i = 0; i<interfaces.length; i++)
Trang 18Listing 4-9 presents the internal implementation of the getInterfaces function
Listing 4-9: The Internal Implementation of the get Interfaces Method
As you can see in this listing, the getInterfaces function takes the following steps:
1 It defines and instantiates a local JavaScript array:
var a = []
2 It assigns the current type to a local variable:
b = this;
3 It accesses the interfaces that the current type implements: As you saw in Listing 4-7 , every type
maintains the list of the interfaces that it implements in an internal array named _interfaces :
var c = b. interfaces;
4 It iterates through the interfaces that the current type implements and adds each enumerated
interface to the local JavaScript array defined in step 1:
a[a.length] = e
5 It assigns the base type of the current type to the local variable defined in step 2, which means
that the base type is now the current type:
b = b. baseType
6 It repeats steps 3, 4, and 5
As these steps show, the getInterfaces method returns all the interfaces that the type and all its
ancestor types implement
Trang 19<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
throw Error.notImplemented();
};
function Department$IEmployee$set_employeeID () {
throw Error.notImplemented();
};
Department.IEmployee.prototype = {
get_employeeID : Department$IEmployee$get_employeeID, set_employeeID: Department$IEmployee$set_employeeID }
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;},
(continued)
Trang 20get_employeeID : function () {return this._employeeID;},
set_employeeID : function (value) {this._employeeID = value;}
Listing 4-10 contains the internal implementation of isInterface isInterface simply returns the
value of the _interface Boolean field discussed earlier This is yet another example of the NET-like
type reflection capabilities of the ASP.NET AJAX client-side framework
Listing 4-10: The Internal Implementation of is Interface
One of the main characteristics of any OOP language is support for the class inheritance The ASP.NET
AJAX client-side framework extends JavaScript to add support for this all-important feature As an
example, Listing 4-11 implements a new class named Department.Manager that inherits the
<form id=”form1” runat=”server”>
<asp:ScriptManager runat=”server” ID=”ScriptManager1” />
<script language=”JavaScript” type=”text/javascript”>
Trang 21function Department$IEmployee$get_employeeID () {
throw Error.notImplemented();
};
function Department$IEmployee$set_employeeID () {
throw Error.notImplemented();
};
Department.IEmployee.prototype = {
get_employeeID : Department$IEmployee$get_employeeID, set_employeeID: Department$IEmployee$set_employeeID }
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}, get_employeeID : function () {return this._employeeID;}, set_employeeID : function (value) {this._employeeID = value;}
}
Department.Employee.registerClass(“Department.Employee”, null, Department.IEmployee);
Department.Manager = function (firstName, lastName, department) {
Department.Manager.initializeBase(this,[firstName,lastName]);
this._department = department;
};
Department.Manager.prototype = {
get_department : function () {return this._department;}, set_department : function (value) {this._department = value;}
Trang 22Listing 4-12: The Manager Constructor in JavaScript
Department.Manager = function (firstName, lastName, department)
{
Department.Manager.initializeBase(this,[firstName,lastName]);
this._department = department;
};
Note that the Manager constructor first calls a method named initializeBase To understand the role
of this method, take a look at the Manager constructor in an OOP language such as C#, as shown in
Listing 4-13
Listing 4-13: The Manager Constructor in C#
public Manager(string firstName, string lastName:base(firstName, lastName),
string department)
this._department = department;
}
The Manager constructor uses the boldfaced syntax shown in Listing 4-13 to call the constructor of its
base class — that is, the Employee class The Manager constructor in the ASP.NET AJAX client-side
framework, on the other hand, uses the boldfaced syntax shown in Listing 4-12 to achieve the same
goal — that is, to call the constructor of the base class Therefore, calling the initializeBase method is
equivalent to calling the base syntax shown in Listing 4-13 I’ll discuss the internal implementation of
the initializeBase method later in this chapter For now, suffice it to say that the constructor of a base
class must first call the initializeBase method
As mentioned, the first order of business in subclassing an existing class such as the Department
.Employee class is to define the constructor of the subclass (see Listing 4-12 ) The next order of business
is to register the subclass with the ASP.NET AJAX client-side framework, like this:
Department.Manager.registerClass(“Department.Manager”, Department.Employee);
Note that you must pass the base class itself as the second parameter of the registerClass method
This tells the ASP.NET AJAX client-side framework that the class being registered is a subclass of the
specified class
Trang 23Because the Department.Manager class derives from the Department.Employee class, it inherits the
get_firstName , set_firstName , get_lastName , and set_lastName methods from its base class You can now instantiate an instance of the Department.Manager class and call these four methods on the instance even though the class itself does not directly contain these four methods:
var mgr = new Department.Manager(“SomeFirstName”, “SomeLastName”, “SomeDepartment”);
var str = ”First Name: “ + mgr.get_firstName() + “\n”;
str += (“Last Name: “ + mgr.get_lastName() + “\n”);
this.prototype.constructor = this;
this. typeName = c;
this. class = true;
if(b) { this. baseType = b;
this. basePrototypePending = true;
}
if(!window. classes) window. classes = [];
window. classes[c.toUpperCase()] = this;
if(d) { this. interfaces = [];
for(var a = 2; a < arguments.length; a ++ ) {
this.prototype[methodName] = method;
} } this. interfaces.push(e);
} } window. registeredTypes[c] = true;
return this;
};
Trang 24The highlighted portion of this code takes the following steps:
1 It assigns the base class to a field named _baseType Think of this field as NET-like metadata,
which allows you to query a type for its base type
this. baseType = b;
2 It sets a Boolean field named _basePrototypePending to true I’ll discuss the significance of
this field in the next section
get BaseType
The getBaseType method enables you to access the _baseType metadata of a specified type
This metadata references the base type of the type Listing 4-15 presents a page that uses the
<form id=”form1” runat=”server”>
<asp:ScriptManager ID=”ScriptManager1” runat=”server” />
<script language=”JavaScript” type=”text/javascript”>
Trang 25set_employeeID: Department$IEmployee$set_employeeID }
get_firstName : function () {return this._firstName;}, set_firstName : function (value) {this._firstName = value;}, get_lastName : function() {return this._lastName;},
set_lastName : function (value) {this._lastName = value;}, get_employeeID : function () {return this._employeeID;}, set_employeeID : function (value) {this._employeeID = value;}
}
Department.Employee.registerClass(“Department.Employee”, null, Department.IEmployee);
Department.Manager = function (firstName, lastName, department) {
Department.Manager.initializeBase(this,[firstName,lastName]);
this._department = department;
};
Department.Manager.prototype = {
get_department : function () {return this._department;}, set_department : function (value) {this._department = value;}
Trang 26Note that this pop-up message shows the following code:
Department.Employee = function (firstName, lastName)
{
var _firstName = firstName;
var _lastName = lastName;
}
This is the boldfaced code shown in Listing 4-15 — that is, the definition of the constructor of the
Department.Employee class As this example shows, the getBaseType method returns a reference
to the actual Department.Employee class
Listing 4-16 presents the internal implementation of the getBaseType method This method simply
returns the value of the _baseType metadata as expected This is yet another example of the runtime
type reflection capabilities of the ASP.NET AJAX client-side framework
Listing 4-16: The get BaseType Method
As you saw in Listing 4-12 , the constructor of every subclass must first call the initializeBase
method As discussed earlier, this method is the ASP.NET AJAX equivalent of the base syntax in C#
(see Listings 4-12 and 4-13 ) As such, the main responsibility of the initializeBase method is to
invoke the constructor of the base class Before diving into the internal implementation of this method,
let’s revisit Listing 4-12 :
Department.Manager = function (firstName, lastName, department)
Trang 27As the highlighted portion of this code shows, the initializeBase method takes two parameters The first parameter references the instance of the subclass that is calling the method The subclass in this case
is the Department.Manager class The second parameter — which is optional — is a JavaScript array that contains the parameters that must be passed into the constructor of the base class
Listing 4-17 presents the internal implementation of the initializeBase method
Listing 4-17: The Internal Implementation of initialize Base
Type.prototype.initializeBase = function(a, b){
this.resolveInheritance();
if(this. baseType) {
if(!b) this. baseType.apply(a);
else this. baseType.apply(a, b);
} return a;
};
This method takes the following steps:
1 It calls a method named resolveInheritance (discussed in more detail in the next section):
this.resolveInheritance();
2 If the current class is indeed a subclass of another class — that is, if _baseType is not null — the
initializeBase method calls the apply method on the constructor of the base class, passing
in the JavaScript array that contains the parameters of this constructor:
if(this. basePrototypePending) {
var b = this. baseType;
b.resolveInheritance();
for(var a in b.prototype)
(continued)