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

JavaScript Bible, Gold Edition part 128 docx

10 165 0
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 146,24 KB

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

Nội dung

The purpose of a getter is to assign a new property to the prototype of an object and to define how the value returned by the property should be evaluated.. The corresponding setter defi

Trang 1

Better ways exist to intercept and preprocess user input, but the watch() func-tion can be a helpful debugging tool when you want to monitor the hidden workings

of scripts

Defining object property getters and setters

A future version of the ECMA-262 language specification will likely include a pair

of facilities called getter and setter Until such time as the formal syntax is finalized,

you can begin to experiment with this technique in NN6 using temporary syntax that adheres to the likely format (but intentionally uses different keywords until the standard is adopted) When the standard is adopted, a subsequent version of NN will include the standard keywords

I introduced the idea of creating a getter and setter for an object briefly in Chapter 14, where the NN6 syntax style extended properties of some W3C DOM objects to include some of the Microsoft-specific (and very convenient) DOM syn-tax Most notably, you can define a getter for any container to return an array of nested elements just like the IE-only document.allcollection

The purpose of a getter is to assign a new property to the prototype of an object and to define how the value returned by the property should be evaluated A setter does the same, but it also defines how a new value assigned to the property should apply the value to the object Both definitions are written in the form of anonymous functions, such that reading or writing an object’s property value can include sophisticated processing for either operation

Getters and setters are assigned to the prototypeproperty of an object, thus enabling you to customize native and DOM objects The NN6 syntax fashions get-ters, setget-ters, and methods of an object’s prototype with the following syntax:

object.prototype. defineGetter (“propName”, function) object.prototype. defineSetter (“propName”, function)

Note that the underscores before and after the method names are actually pairs

of underscore characters (that is, _, _, defineGetter, _, _) This double under-score was chosen as a syntax that the ECMA standard will not use, so it will not conflict with the eventual syntax for this facility

The first parameter of the method is the name of the property for which the get-ter or setget-ter is defined This can be an existing property name that you want to override The second parameter can be a function reference; but more likely it will

be an anonymous function defined in place By using an anonymous function, you can take advantage of the context of the object for which the property is defined For each property, define both a getter and setter — even if the property is meant to

be read-only or write-only

To see how this mechanism works, let’s use the getter and setter shown in Chapter 14 to add an innerTextproperty to HTML elements in NN6 This property

is read/write, so functions are defined for both the getter and setter The getter defi-nition is as follows:

HTMLElement.prototype. defineGetter (“innerText”, function () { var rng = document.createRange()

rng.selectNode(this) return rng.toString() })

Trang 2

The modified object is the basic HTMLElementobject — the object that NN6 uses

to create instances of every HTML element for the page After the statement above

executes, every HTML element on the page inherits the new innerTextproperty

Each time the innerTextproperty is read for an element, the anonymous function

in this getter executes Thus, after a text range object is created, the range is set to

the node that is the current element This is an excellent example of how the

con-text of the current object allows the use of the thiskeyword to refer to the very

same object Finally, the string version of the selected range is returned It is

essen-tial that a getter function include a returnstatement and that the returned value is

of the desired data type Also take notice of the closing of the function’s curly brace

and the getter method’s parenthesis

By executing this function each time the property is read, the getter always

returns the current state of the object If content of the element has changed since

the page loaded, you are still assured of getting the current text inside the element

This is far superior to simply running the statements inside this function once as

the page loads to capture a static view of the element’s text

The corresponding setter definition is as follows:

HTMLElement.prototype. defineSetter (“innerText”, function (txt) {

var rng = document.createRange()

rng.selectNodeContents(this)

rng.deleteContents()

var newText = document.createTextNode(txt)

this.appendChild(newText)

return txt

})

To assign a value to an object’s property, the setter function requires that a

parameter variable receive the assigned value That parameter variable plays a role

somewhere within the function definition For this particular setter, the current

object (this) also manipulates the text range object The contents of the current

element are deleted, and a text node comprising the text passed as a parameter is

inserted into the element To completely simulate the IE behavior of setting the

innerTextproperty, the text is returned While setters don’t always return values,

this one does so that the expression that assigns a value to the innerText

prop-erty evaluates to the new text

If you want to create a read-only property, you still define a setter for the

prop-erty but you also assign an empty function, as in:

Node.prototype. defineSetter (“all”, function() {})

This prevents assignment statements to a read-only property from generating

errors A write-only property should also have a getter that returns nullor an

empty string, as in:

HTMLElement.prototype. defineGetter (“outerHTML”, function() {return “”})

Because the getter and setter syntax shown here is unique to NN6, you must

obviously wrap such statements inside object detection or browser version

detection statements And, to reiterate, this syntax will change in future browser

versions once ECMA adopts the formal syntax

Trang 3

Using custom objects

There is no magic to knowing when to use a custom object instead of an array in your application The more you work with and understand the way custom objects work, the more likely you will think about your data-carrying scripts in these terms — especially if an object can benefit from having one or more methods asso-ciated with it This avenue is certainly not one for beginners, but I recommend that you give custom objects more than a casual perusal once you gain some

JavaScripting experience

Object-Oriented Concepts

As stated several times throughout this book, JavaScript is object-based rather than object-oriented Instead of adhering to the class, subclass, and inheritance schemes of object-oriented languages such as Java, JavaScript uses what is called

prototype inheritance This scheme works not only for native and DOM objects but

also for custom objects

Adding a prototype

A custom object is frequently defined by a constructor function, which typically parcels out initial values to properties of the object, as in the following example:

function car(plate, model, color) { this.plate = plate

this.model = model this.color = color }

var car1 = new car(“AB 123”, “Ford”, “blue”)

NN4+ and IE4+ offer a handy shortcut, as well, to stuff default values into proper-ties if none are provided (the supplied value is null, 0, or an empty string) The OR

operator (||) can let the property assignment statement apply the passed value, if present, or a default value you hard-wire into the constructor Therefore, you can modify the preceding function to offer default values for the properties:

function car(plate, model, color) { this.plate = plate || “missing”

this.model = model || “unknown”

this.color = color || “unknown”

} var car1 = new car(“AB 123”, “Ford”, “”)

After the preceding statements run, the car1object has the following properties:

car1.plate // value = “AB 123”

car1.model // value = “Ford”

car1.color // value = “unknown”

If you then add a new property to the constructor’s prototypeproperty, as in

car.prototype.companyOwned = true

Trang 4

any carobject you already created or are about to create automatically inherits

the new companyOwnedproperty and its value You can still override the value of

the companyOwnedproperty for any individual carobject But if you don’t override

the property for instances of the carobject, the carobjects whose companyOwned

property is not overridden automatically inherit any change to the prototype

companyOwnedvalue This has to do with the way JavaScript looks for prototype

property values

Prototype inheritance

Each time your script attempts to read or write a property of an object,

JavaScript follows a specific sequence in search of a match for the property name

The sequence is as follows:

1 If the property has a value assigned to the current (local) object, this is the

value to use

2 If there is no local value, check the value of the property’s prototype of the

object’s constructor

3 Continue up the prototype chain until either a match of the property is found

(with a value assigned to it) or the search reaches the native Objectobject

Therefore, if you change the value of a constructor’s prototypeproperty and

you do not override the property value in an instance of that constructor,

JavaScript returns the current value of the constructor’s prototypeproperty

Nested objects and prototype inheritance

When you begin nesting objects, especially when one object invokes the

con-structor of another, there is an added wrinkle to the prototype inheritance chain

Let’s continue with the carobject defined earlier In this scenario, consider the car

object to be akin to a root object that has properties shared among two other types

of objects One of the object types is a company fleet vehicle, which needs the

properties of the root carobject (plate, model, color) but also adds some

prop-erties of its own The other object that shares the carobject is an object

represent-ing a car parked in the company garage — an object that has additional properties

regarding the parking of the vehicle This explains why the carobject is defined on

its own

Now look at the constructor function for the parking record, along with the

con-structor for the basic carobject:

function car(plate, model, color) {

this.plate = plate || “missing”

this.model = model || “unknown”

this.color = color || “unknown”

}

function carInLot(plate, model, color, timeIn, spaceNum) {

this.timeIn = timeIn

this.spaceNum = spaceNum

this.carInfo = car

this.carInfo(plate, model, color)

}

Trang 5

The carInLotconstructor not only assigns values to its unique properties (timeInand spaceNum), but it also includes a reference to the carconstructor arbitrarily assigned to a property called carInfo This property assignment is merely a conduit that allows property values intended for the carconstructor to be passed within the carInLotconstructor function To create a carInLotobject, use

a statement like the following:

var car1 = new carInLot(“AA 123”, “Ford”, “blue”, “10:02AM”, “31”)

After this statement, the car1object has the following properties and values:

car1.timeIn // value = “10:02AM”

car1.spaceNum // value = “31”

car1.carInfo // value = reference to car object constructor function car1.plate // value = “AA 123”

car1.model // value = “Ford”

car1.color // value = “blue”

Let’s say that five carInLotobjects are created in the script (car1through

car5) The prototype wrinkle comes into play if, for example, you assign a new property to the carconstructor prototype:

car.prototype.companyOwned = true

Even though the carInLotobjects use the carconstructor, the instances of

carInLotobjects do not have a prototype chain back to the carobject As the pre-ceding code stands, even though you’ve added a companyOwnedproperty to the

carconstructor, no carInLotobject inherits that property (even if you were to create a new carInLotobject after defining the new prototypeproperty for car)

To get the carInLotinstances to inherit the prototype.companyOwnedproperty, you must explicitly connect the prototype of the carInLotconstructor to the car

constructor prior to creating instances of carInLotobjects:

carInLot.prototype = new car()

The complete sequence, then, is as follows:

function car(plate, model, color) { this.plate = plate || “missing”

this.model = model || “unknown”

this.color = color || “unknown”

} function carsInLot(plate, model, color, timeIn, spaceNum) { this.timeIn = timeIn

this.spaceNum = spaceNum this.carInfo = car this.carInfo(plate, model, color) }

carsInLot.prototype = new car() var car1 = new carsInLot(“123ABC”, “Ford”,”blue”,”10:02AM”, “32”) car.prototype.companyOwned = true

After this stretch of code runs, the car1object has the following properties and values:

Trang 6

car1.timeIn // value = “10:02AM”

car1.spaceNum // value = “31”

car1.carInfo // value = reference to car object constructor function

car1.plate // value = “AA 123”

car1.model // value = “Ford”

car1.color // value = “blue”

car1.companyOwned // value = true

NN4+ provides one extra, proprietary bit of syntax in this prototype world The

proto property (that’s with double underscores before and after the word

“proto”) returns a reference to the object that is next up the prototype chain For

example, if you inspect the properties of car1. proto after the preceding code

runs, you see that the properties of the object next up the prototype chain are as

follows:

car1. proto .plate // value = “AA 123”

car1. proto .model // value = “Ford”

car1. proto .color // value = “blue”

car1. proto .companyOwned // value = true

This property can be helpful in debugging custom objects and prototype

inheri-tance chain challenges, but the property is not part of the ECMA standard

Therefore, I discourage you from using the property in your production scripts

Object Object

Properties Methods

constructor hasOwnProperty()

prototype isPrototypeOf()

propertyIsEnumerable() toLocaleString() toString() valueOf()

Syntax

Creating an object object:

function constructorName([arg1, [,argN]]) {

statement(s)

}

var objName = new constructorName([“argName1”, [,”argNameN”])

var objName = new Object()

var objName = {propName1:propVal1[, propName2:propVal2[, N]}}

objectObject

Trang 7

Accessing an object object properties and methods:

objectReference.property | method([parameters])

NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5

About this object

While it might sound like doubletalk, the Objectobject is a vital native object in the JavaScript environment It is the root object on which all other native objects — such as Date, Array, String, and the like — are based This object also provides the foundation for creating custom objects, as described earlier in this chapter

By and large, your scripts do not access the properties of the native Object

object The same is true for many of its methods, such as toString()and

valueOf(), which internally allow debugging alert dialog boxes (and The Evaluator) to display something when referring to an object or its constructor You can use a trio of methods, described next, in IE5.5 and NN6 to perform some inspection of the prototype environment of an object instance They are of interest primarily to advanced scripters who are building extensive, simulated object-oriented applications

Methods

hasOwnProperty(“propName”)

Returns: Boolean.

NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5

The hasOwnProperty()method returns trueif the current object instance has the property defined in its constructor or in a related constructor function But if this property is defined externally, as via assignment to the object’s prototype

property, the method returns false Using the example of the carand carInLotobjects from earlier in this chapter, the following expressions evaluate to true:

car1.hasOwnProperty(“spaceNum”) car1.hasOwnProperty(“model”)

Even though the modelproperty is defined in a constructor that is invoked by another constructor, the property belongs to the car1object The following state-ment, however, evaluates to false:

car1.hasOwnProperty(“companyOwned”)

This property is defined by way of the prototype of one of the constructor func-tions and is not a built-in property for the object instance

objectObject.hasOwnProperty()

Trang 8

Returns: Boolean.

NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5

The isPrototypeOf()method is intended to reveal whether or not the current

object has a prototype relation with an object passed as a parameter In practice,

the IE5.5 and NN6 versions of this method not only operate differently, but they also

do not appear in either browser to report prototype relationships correctly

between objects If any updated information is available for this method within

these browsers, I will post it to the JavaScript Bible Support Center at

http://www.dannyg.com/update.html

propertyIsEnumerable(“propName”)

Returns: Boolean.

NN2 NN3 NN4 NN6 IE3/J1 IE3/J2 IE4 IE5 IE5.5

In the terminology of the ECMA-262 language specification, a value is enumerable

if constructions such as the for-inproperty inspection loop (Chapter 39) can

inspect it Enumerable properties include values such as arrays, strings, and

virtu-ally every kind of object According to the ECMA specification, this method is not

supposed to work its way up the prototype chain IE5.5 appears to adhere to this,

whereas NN6 treats a property inherited from an object’s prototype as a valid

parameter value

objectObject.propertyIsEnumerable()

Trang 10

Global Functions

and Statements

In addition to all the objects and other language constructs

described in the preceding chapters of this reference part

of the book, several language items need to be treated on a

global scale These items apply to no particular objects (or

any object), and you can use them anywhere in a script If you

read earlier chapters, you were introduced to many of these

functions and statements This chapter serves as a

conve-nient place to highlight these all-important items that are

oth-erwise easily forgotten At the end of the chapter, note the

brief introduction to several objects that are built into the

Windows-only versions of Internet Explorer Some of these

objects have pointers to more details at Microsoft’s Web site

This chapter begins with coverage of the following global

functions and statements that are part of the core JavaScript

language:

Functions Statements

decodeURI() // and /* */ (comment)

decodeURIComponent() const

encodeURI() var

encodeURIComponent()

escape()

eval()

isFinite()

isNaN()

Number()

parseFloat()

parseInt()

toString()

unescape()

unwatch()

watch()

42

In This Chapter

Converting strings into object references

Creating URL-friendly strings

Adding comments to scripts

Ngày đăng: 06/07/2014, 06:20