1. Trang chủ
  2. » Công Nghệ Thông Tin

ASP.NET AJAX Programmer’s Reference - Chapter 4 doc

54 434 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề JavaScript Object-Oriented Programming and Type Reflection Extensions
Trường học University of Example
Chuyên ngành Computer Science
Thể loại Document
Năm xuất bản 2007
Thành phố Unknown
Định dạng
Số trang 54
Dung lượng 341,35 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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 1

JavaScript 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 2

JavaScript 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 3

Every 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 4

As 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 5

register 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 6

Listing 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 7

4 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 8

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;}

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 9

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;}

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 10

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;}

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 11

Listing 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 12

is 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 14

Listing 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 15

being 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 16

The 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 18

Listing 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 20

get_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 21

function 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 22

Listing 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 23

Because 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 24

The 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 25

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 26

Note 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 27

As 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)

Ngày đăng: 09/08/2014, 06:23