Tải bản đầy đủ (.pdf) (25 trang)

Objects

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (236.2 KB, 25 trang )

Chapter 8. Objects
Chapter 3 explained that objects are one of the funda
are also one of the most important. This chapter describes JavaScript objects in
mental data types in JavaScript.
etail. Basic usage of objects, described in the next section, is straightforward, but as
we'll see in later sections, objects have more complex uses and behaviors.
Properties
ultiple values into a single unit and
followed by the name of
an create an
newly created
tructor initializes an
// The current date and
sents December 31,
They
d
8.1 Objects and
Objects are composite data types: they aggregate m
allow us to store and retrieve those values by name. Another way to explain this is to say
that an object is an unordered collection of properties, each of which has a name and a
value. The named values held by an object may be primitive values like numbers and
strings, or they may themselves be objects.
8.1.1 Creating Objects
Objects are created with the new operator. This operator must be
a constructor function that serves to initialize the object. For example, we c
roperties) like this:empty object (an object with no p
var o = new Object( );
JavaScript supports other built-in constructor functions that initialize
objects in other, less trivial, ways. For example, the Date( ) cons
ime:object that represents a date and t
var now = new Date( );


time
var new_years_eve = new Date(2000, 11, 31); // Repre
2000
Later in this chapter, we'll see that it is possible to define custom constructor methods to
initialize newly created objects in any way you desire.
Object literals provide another way to create and initialize new objects. As we saw in
Chapter 3, an object literal allows us to embed an object description literally in JavaScrip
code in much the same way that we embed textual data into JavaScri
t
pt code as quoted
d list of property specifications
ion in an object literal consists of
e followed by a colon and the property value. For example:
var circle = { x:0, y:0, radius:2 }
var homer = {
strings. An object literal consists of a comma-separate
nclosed within curly braces. Each property specificate
the property nam
name: "Homer Simpso
age: 34,
n",
The object literal syntax is defined by the ECMAScript v3 specification and implemented
normally use the . operator to access the value of an object's properties. The value
on the left of the . should be a reference to an object (usually just the name of the
the
r
perty p in object o with o.p or to the property radius
in the object circle with circle.radius. Object properties work like variables: you can
from them. For example:
ject.

book.title = "JavaScript: The Definitive Guide"
ct( );
ntroduction to JavaScript";
ook.chapter1.pages = 19;
book.chapter2 = { title: "Lexical Structure", pages: 6 };
.chapter2.title);
out this example is that you can create a new property of
married: true,
occupation: "plant operator",
email: ""
};
in JavaScript 1.2 and later.
8.1.2 Setting and Querying Properties
You
variable that contains the object reference). The value on the right of the . should be
name of the property. This must be an identifier, not a string or an expression. Fo
example, you would refer to the pro
store values in them and read values
// Create an object. Store a reference to it in a variable.
var book = new Object( );
// Set a property in the ob
// Set some more properties. Note the nested objects.
book.chapter1 = new Obje
ook.chapter1.title = "Ib
b
// Read some property values from the object.
alert("Outline: " + book.title + "\n\t" +
"Chapter 1 " + book.chapter1.title + "\n\t" +
"Chapter 2 " + book
An important point to notice ab

an object simply by assigning a value to it. Although we declare variables with the
var
keyword, there is no need (and no way) to do so with object properties. Furthermore,
once you have created an object property by assigning a value to it, you can change the
value of the property at any time simply by assigning a new value:
book.title = "JavaScript: The Rhino Book"
8.1.3 Enumerating Properties
The for/in loop discussed in Chapter 6 provides a way to loop through, or enumerate,
the properties of an object. This can be useful when debugging scripts or when working
wit b hose names you do not know in
adv c
an obje
function DisplayPropertyNames(obj) {
mes);
r, and
defined properties, it does not enumerate certain
ethods.
.4 Undefined Properties
ords, a
ing the undefined
h o jects that may have arbitrary properties w
an e. The following code shows a function you can use to list the property names of
ct:
var names = "";
for(var name in obj) names += name + "\n";
alert(na
}
Note that the loop does not enumerate properties in any specific ordefor/in
hough it enumerates all user-alt
predefined properties or m

8.1
If you attempt to read the value of a property that does not exist (in other w
property that has never had a value assigned to it), you end up retriev
value (introduced in Chapter 3).
You can use the delete operator to delete a property of an object:
We saw previously that you c a new object in JavaScript by using
t(
pes
pl
you are writing a program that manipulates rectangles, y ight want to represent
l type, or class, of object. Each object of this Rectangle class
operty and a height property, since those are the essential
defining characteristics of rectangles.
delete book.chapter2;
Note that deleting a property does not merely set the property to undefined; it actually
removes the property from the object. The for/in loop demonstrates this difference: it
enumerates properties that have been set to the undefined value, but it does not
enumerate deleted properties.
8.2 Constructors
an create and initialize
the new operator in conjunction with a predefined constructor function such as Objec
), Date( ), or Function( ). These predefined constructors and the built-in object ty
they create are useful in many instances. However, in object-oriented programming, it is
also common to work with custom object types defined by your program. For exam e, if
ou m
rectangles with a specia
would have a width pr
To create objects with properties such as width and height already defined, we need to
write a constructor to create and initialize these properties in a new object. A construct
is a JavaScript function with two special features:

x It is invoked through the
or
w operator.
x It is passed a reference to a newly created, empty object as the value of the this
ord, and it is responsible for performing appropriate initialization for that
new object.
ne
keyw
Example 8-1 shows how the constructor function for a Rectangle object might be defined
and invoked.
xample 8-1. A Rectangle object constructor function
"this".
function Rectangle(w, h)
this.width = w;
this.height = h;
can i ize each new object appropriately.
defining an appropriate constructor function
constructor are now guaranteed to have
width and height properties. This means that we can write programs that rely
es a
lize the object
w
E
// Define the constructor.
// Note how it initializes the object referred to by
{
}
// Invoke the constructor to create two Rectangle objects.
// We pass the width and height to the constructor,
// so it nitial

var rect1 = new Rectangle(2, 4);
var rect2 = new Rectangle(8.5, 11);
Notice how the constructor uses its arguments to initialize properties of the object
referred to by the this keyword. Keep in mind that a constructor function simply
initializes the specified object; it does not have to return that object.
We have defined a class of objects simply by
- all objects created with the Rectangle( )-
initialized
on this fact and treat all Rectangle objects uniformly. Because every constructor defin
class of objects, it is stylistically important to give a constructor function a name that
indicates the class of objects it creates. Creating a rectangle with
new Rectangle(1,2) is
a lot more intuitive than with new init_rect(1,2), for example.
Constructor functions typically do not have return values. They initia
passed as the value of this and return nothing. However, a constructor is allowed to
return an object value, and, if it does so, that returned object becomes the value of the ne
expression. In this case, the object that was the value of this is simply discarded.
8.3 Methods
A method is nothing more than a JavaScript function that is invoked through an object
Recall that functions are data values and that there is nothing s al ab
.
peci out the names
with which they are defined -- a function can be assigned to any variable, or even to any
o.m = f;
if m( ) expects two arguments, we might invoke it like this:
voked
yword within the body of the method. For example,
o with the this
this keyword should begin to clarify why we use methods at all.
n the object , but the

the
ions are
al
keyword refers to the global object. Thus,
ns and methods. The real difference lies in
property of an object. If we have a function
f and an object o, we can define a method
named m with the following line:
Having defined the method m( ) of the object o, we invoke it like this:
o.m( );
Or,
o.m(x, x+2);
Methods have one very important property: the object through which a method is in
becomes the value of the this ke
when we invoke o.m( ), the body of the method can refer to the object
keyword.
The discussion of the
Any function that is used as a method is effectively passed an extra argument -- the object
through which it is invoked. Typically, a method performs some sort of operation on that
object, so the method invocation syntax is a particularly elegant way to express the fact
that a function is operating on an object. Compare the following two lines of code:
rect.setSize(width, height);
setRectSize(rect, width, height);
These two lines may perform exactly the same operation o rect
method invocation syntax in the first line more clearly indicates the idea that it is
object rect that is the primary focus, or target, of the operation. (If the first line does not
seem a more natural syntax to you, you are probably new to object-oriented
programming. With a little experience, you will learn to love it!)
While it is useful to think of functions and methods differently, there is not actually as
much difference between them as there initially appears to be. Recall that funct

values stored in variables and that variables are nothing more than properties of a glob
a function, you are actually invoking a method of the object. Thus, when you invoke
global object. Within such a function, the this
rence between functiothere is no technical diffe
design and intent: methods are written to operate som
use the
ehow on the this object, while
this object.
ed through an example. Example 8-
functions usually stand alone and do not
The typical usage of methods is more clearly illustrat
2 returns to the Rectangle objects of Example 8-1 and shows how a method that operates
ked.
s keyword, so it doesn't make sense to
f; it needs instead to be made a method of some
" and "height" properties defined.
return this.width * this.height;
5
on Rectangle objects can be defined and invo
Example 8-2. Defining and invoking a method
// This function uses the thi
// invoke it by itsel
// object that has "width
function compute_area( )
{
}
// Create a new Rectangle object, using the constructor defined
earlier.
var page = new Rectangle(8.5, 11);
// Define a method by assigning the function to a property of the

object.
page.area = compute_area;
// Invoke the new method like this:
var a = page.area( ); // a = 8.5*11 = 93.
One shortcoming is evident in Example 8-2: before you can invoke the area( ) method
for the rect object, you must assign that method to a property of the object. While we
can invoke the area( ) method on the particular object named page, we can't invoke it
on any other Rectangle objects without first assigning the method to them. This quickly
becomes tedious. Example 8-3 defines some additional Rectangle methods and show
how they can automatically be assigned to all Rectangle objects with a constructor
function.
s
Example 8-3. Defining methods in a constructor
// First, define some functions that will be used as methods.
his.height *= 2; }
is.height /= 2; }
this.height = h;
function Rectangle_area( ) { return this.width * this.height; }
function Rectangle_perimeter( ) { return 2*this.width + 2*this.height;
}
function Rectangle_set_size(w,h) { this.width = w; this.height = h; }
function Rectangle_enlarge( ) { this.width *= 2; t
function Rectangle_shrink( ) { this.width /= 2; th
// Then define a constructor method for our Rectangle objects.
// The constructor initializes properties and also assigns methods.
function Rectangle(w, h)
{
// Initialize object properties.
this.width = w;
// Define methods for the object.

this.area = Rectangle_area;
this.perimeter = Rectangle_perimeter;
this.set_size = Rectangle_set_size;
this.enlarge = Rectangle_enlarge;
this.shrink = Rectangle_shrink;
}
// Now, when we create a rectangle, we can immediately invoke methods
on it:
var r = new Rectangle(2,2);
var a = r.area( );
r.enlarge( );
var p = r.perimeter( );
The technique shown in Example 8-3 also has a shortcoming. In this example, the
Rectangle( ) constructor sets seven properties of each and every Rectangle object it
r
cts
ass.
initializes, even though five of those properties have constant values that are the same fo
every rectangle. Each property takes up memory space; by adding methods to our
Rectangle class, we've more than tripled the memory requirements of each Rectangle
object. Fortunately, JavaScript has a solution to this problem: it allows an object to inherit
properties from a prototype object. The next section describes this technique in detail.
8.4 Prototypes and Inheritance
We've seen how inefficient it can be to use a constructor to assign methods to the obje
it initializes. When we do this, each and every object created by the constructor has
identical copies of the same method properties. There is a much more efficient way to
specify methods, constants, and other properties that are shared by all objects in a cl
JavaScript objects "inherit" properties from a prototype object.
[1]
Every object has a

prototype; all of the properties of the prototype object appear to be properties of any
objects for which it is a prototype. That is, each object inherits properties from its
prototype.
[1]
Prototypes were introduced in Java
he prototype of an object is defined by the constructor function that was used to create
and initialize the object. All functions in JavaScript have a property that
es
Script 1.1; they are not supported in the now obsolete JavaScript 1.0.
T
prototype
refers to an object. This prototype object is initially empty, but any properties you define
in it will be inherited by all objects created by the constructor.
A constructor defines a class of objects and initializes properties, such as width and
height, that are the state variables for the class. The prototype object is associated with
the constructor, so each member of the class inherits exactly the same set of properti
from the prototype. This means that the prototype object is an ideal place for methods and
other constant properties.
Note that inheritance occurs automatically, as part of the process of looking up a proper
value. Properties are
ty
ly
ount of memory
required by each object, since the object can inherit many of its properties. The second
tially
one
property
p of an object o, JavaScript first checks to see if o has a property named p. If it
otype object of o has a property named p. This is
work.

to set the property of the prototype. Now you have changed
t when you
om its
a new property p directly in o. Now that o has
hen
p
e of p
p o "shadows" or "hides" the
Figure
not copied from the prototype object into new objects; they mere
appear as if they were properties of those objects. This has two important implications.
First, the use of prototype objects can dramatically decrease the am
implication is that an object inherits properties even if they are added to its prototype
after the object is created.
Each class has one prototype object, with one set of properties. But there are poten
many instances of a class, each of which inherits those prototype properties. Because
prototype property can be inherited by many objects, JavaScript must enforce a
fundamental asymmetry between reading and writing property values. When you read
does not, it next checks to see if the prot
hat makes prototype-based inheritancew
When you write the value of a property, on the other hand, JavaScript does not use the
prototype object. To see why, consider what would happen if it did: suppose you try to
set the value of the property o.p when the object o does not have a property named p.
Further suppose that JavaScript goes ahead and looks up the property p in the prototype
object of o and allows you
the value of p for a whole class of objects -- not at all what you intended.
Therefore, property inheritance occurs only when you read property values, no
bject o that inherits that property frwrite them. If you set the property p in an o
you create prototype, what happens is that
its own property named p, it no longer inherits the value of p from its prototype. W

you read the value of p, JavaScript first looks at the properties of o. Since it finds
t and never finds the valudefined in o, it doesn't need to search the prototype objec
ined there. We sometimes say that the property in def
property
p in the prototype object. Prototype inheritance can be a confusing topic.
8-1 illustrates the concepts we've discussed here.
Figure 8-1. Objects and prototypes
Because prototype properties are shared by all objects of a class, it generally makes sense
to use them only to define properties that are the same for all objects within the class.
es
you
at represent
circles. The prototype object for this class is
Circle.prototype,
[2]
This makes prototypes ideal for defining methods. Other properties with constant valu
(such as mathematical constants) are also suitable for definition with prototype
properties. If your class defines a property with a very commonly used default value,
might define this property and its default value in a prototype object. Then, the few
objects that want to deviate from the default value can create their own private, unshared
copies of the property and define their own nondefault values.
Let's move from an abstract discussion of prototype inheritance to a concrete example.
Suppose we define a
Circle( ) constructor function to create objects th
so we can define a
) constructor but have not yet used it to create any Circle objects, we'd define the constant property pi like this:
constant available to all Circle objects like this:
[2]
The prototype object of a constructor is created automatically by JavaScript. In most versions of JavaScript, every function is automatically
given an empty prototype object, just in case it is used as a constructor. In JavaScript 1.1, however, the prototype object is not created until the

function is used as a constructor for the first time. This means that if you require compatibility with JavaScript 1.1, you should create at least
one object of a class before you use the prototype object to assign methods and constants to objects of that class. So, if we have defined a
Circle(
//First create and discard a dummy object; forces prototype object
creation. new Circle ( ); //Now we can set properties in the protot
Circle.prototype.pi = 3.14159'
ype.
Circle.prototype.pi = 3.14159;
Example 8-4 shows our Circle example fully fleshed out. The code defines a Circle
class by first defining a Circle( ) constructor to initialize each individual object and
then setting properties of
ss.
Example 8-4. Defining a Circle
.x = x; // The X-coordinate of the center of the circle
Script 1.1.
// First declare a function, then assign it to a prototype property.
// Define another method. This time we use a function literal to define
t to a prototype property all in one step.
Circle.prototype
to define methods and constants shared by
all instances of the cla
class with a prototype object
// Define a constructor method for our class.
// Use it to initialize properties that will be different for
// each individual Circle object.
function Circle(x, y, r)
{
this
this.y = y; // The Y-coordinate of the center of the circle
this.r = r; // The radius of the circle

}
// Create and discard an initial Circle object.
// This forces the prototype object to be created in Java
new Circle(0,0,0);
// Define a constant: a property that will be shared by
// all circle objects. Actually, we could just use Math.PI,
// but we do it this way for the sake of instruction.
Circle.prototype.pi = 3.14159;
// Define a method to compute the circumference of the circle.
// Note the use of the constant defined above.
function Circle_circumference( ) { return 2 * this.pi * this.r; }
Circle.prototype.circumference = Circle_circumference;
// the function and assign i
Circle.prototype.area = function( ) { return this.pi * this.r *
this.r; }
// The Circle class is defined.
// Now we can create an instance and invoke its methods.
var c = new Circle(0.0, 0.0, 1.0);
var a = c.area( );
var p = c.circumference( );

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×