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

Practical prototype and scipt.aculo.us part 8 potx

6 266 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 6
Dung lượng 101,64 KB

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

Nội dung

This is a fine and decent way to loop, but JavaScript is capable of so much more!A language with JavaScript’s expressive power can embrace functional programming concepts to make iterati

Trang 1

You can do far more with Prototype than what I’ve just described, but the functions in

this chapter are the ones you’ll use most often And although they solve common

prob-lems, they also form the foundation for a general scripting philosophy: one that espouses

fewer lines of code, separation of content and behavior, and the principle of least

sur-prise Later on, you’ll learn how to use these functions within a set of conventions to

make your DOM scripting experience far more pleasant

C H A P T E R 2 ■ P R OTOT Y P E B A S I C S 29

Trang 2

Collections (Or, Never Write a

for Loop Again)

Collections are at the heart of DOM scripting—arrays, hashes, DOM NodeLists, and

various other groups of items Nearly all your scripts will do some form of iteration over

an array So why is iteration so bland in JavaScript?

Prototype sports a robust library for dealing with collections It makes arrays

astoundingly flexible (and invents Hash, a subclass of Object, for key/value pairs), but

can also be integrated into any collections you use in your own scripts

The Traditional for Loop

Amazingly, the first version of JavaScript didn’t even support arrays They were added

soon after, but with only one real enhancement over a vanilla Object—a magic length

property that would count the number of numeric keys in the array For example

var threeStooges = new Array();

threeStooges[0] = "Larry";

threeStooges[1] = "Curly";

threeStooges[2] = "Moe";

console.log(threeStooges.length);

//-> 3

The lengthproperty and the ubiquitous forlooping construct result in a simple,

low-tech way to loop over an array’s values: start at 0and count up to the value of length

for (var i = 0; i < threeStooges.length; i++) {

console.log(threeStooges[i] + ": Nyuk!");

}

31

Trang 3

This is a fine and decent way to loop, but JavaScript is capable of so much more!

A language with JavaScript’s expressive power can embrace functional programming

concepts to make iteration smarter

Functional Programming

JavaScript is a multi-paradigm language It can resemble the imperative style of C, the object-oriented style of Java, or the functional style of Lisp To illustrate this, let’s define

a function and see what it can do:

function makeTextRed(element) {

element.style.color = "red";

}

This function expects a DOM element node and does exactly what it says: it turns the node’s enclosed text red To apply this function to an entire collection of nodes, we can use the venerable forloop:

var paragraphs = $$('p');

for (var i = 0; i < elements.length; i++)

makeTextRed(elements[i]);

But let’s look at this from another angle You learned in Chapter 1 that functions in JavaScript are “first-class objects,” meaning that they can be treated like any other data type, like so:

typeof makeTextRed //-> "function"

makeTextRed.constructor; //-> Function

var alias = makeTextRed;

alias == makeTextRed; //-> true

In short, anything that can be done with strings, numbers, or other JavaScript data types can be done with functions

This enables a different approach to iteration: since functions can be passed as arguments to other functions, you can define a function for iterating over an array Again, this is easier to explain with code than with words:

function each(collection, iterator) {

for (var i = 0; i < collection.length; i++)

iterator(collection[i]);

}

C H A P T E R 3 ■ C O L L E C T I O N S ( O R , N E V E R W R I T E A F O R L O O P A G A I N )

32

Trang 4

The iteratorargument is a function The eachmethod we just wrote will loop over an

array’s indices and call iteratoron each, passing into it the current item in the array

Now we can iterate thusly:

var paragraphs = $$('p');

each(paragraphs, makeTextRed);

Also remember from Chapter 1 that functions have a literal notation—you don’t have

to name a function before you use it If we won’t use the makeTextRedfunction anywhere

else in the code, then there’s no reason to define it beforehand

each(paragraphs, function(element) {

element.style.color = "red";

});

We can make one more improvement to our code Since each is a method made to

act on arrays, let’s make it an instance method of all arrays:

Array.prototype.each = function(iterator) {

for (var i = 0; i < this.length; i++)

iterator(this[i]);

};

Remember that thisrefers to the execution scope of the function—in this case, it’s

the array itself Now we can write the following:

paragraphs.each(function(element) {

element.style.color = "red";

});

To look at this more broadly, we’ve just abstracted away the implementation details

of iteration Under the hood, we’re calling the same old forloop, but because we’ve built

a layer on top, we’re able to define other functions that involve iterating but do much

more than the preceding eachexample

ABOUT FUNCTION NOTATION

This book uses a common notation to distinguish between static methods and instance methods Static

methods are marked with a dot—for example,Array.fromrefers to the frommethod on the Array

object Instance methods are marked with an octothorpe:Array#eachrefers to the eachmethod on

Array.prototype—that is, a method on an instance of Array

Trang 5

Prototype’s Enumerable Object

Prototype defines a handful of functions in an object called Enumerable Anything that is

“enumerable” (anything that can be iterated over) can use these methods

These functions include each(much like the one we defined previously) and many other methods that all hook into eachinternally These methods aren’t specific to

arrays—they can be used on any collection, as long as we tell them how to enumerate

the items therein

Prototype automatically extends Enumerableonto Array At the end of the chapter, you’ll learn how to implement Enumerablein your own classes, but for now we’ll use arrays for all our examples

Using Enumerable#each

Enumerable#eachis the foundation that the rest of Enumerablerelies upon, so let’s take

a closer look at it

I’ve been defaming forloops for several pages now, but they do have one critical advantage over functional iteration: they let you short-circuit the iteration flow by using the keywords break(abort the loop) and continue(skip to the next item in the loop) We need a way to emulate these keywords if we want to match the feature set

of traditional loops

var elements = $$('.menu-item');

// find the element whose text content contains "weblog"

for (var i = 0, element; element = elements[i]; i++) {

if (!element.id) continue;

if (element.innerHTML.include('weblog')) break;

}

Simulating continueis easy enough—an empty return within a function will do the trick:

var elements = $$('.menu-item'), weblogElement;

elements.each( function(element) {

if (!element.id) return;

/* */

});

But a breakequivalent takes a bit of voodoo Prototype makes smart use of excep-tions to pull this off It creates a $breakobject that can be thrown within loops to exit immediately

C H A P T E R 3 ■ C O L L E C T I O N S ( O R , N E V E R W R I T E A F O R L O O P A G A I N )

34

Trang 6

var elements = $$('.menu-item'), weblogElement;

elements.each( function(element) {

if (!element.id) return;

if (element.innerHTML.include('weblog')) {

weblogElement = element;

throw $break;

}

});

In this example, we “throw” the $breakobject as though it were an exception It

interrupts the execution of the function and gets “caught” higher in the call stack, at

which point the eachmethod stops iterating and moves on

Now we’re even It’s rare that you’ll need to use $break—most of the use cases for

breaking out of loops are addressed by other Enumerablemethods—but it’s comforting

to know it’s there

Finding Needles in Haystacks: detect, select,

reject, and partition

The code pattern we used in the last section—finding one needle in a haystack—is a

common one, but we can express it more concisely than through an eachloop The

function we pass into eachserves as an item manipulator, but we can also use that

function as a litmus test to let us know whether an item matches our needle The next

four methods do just this

Using Enumerable#detect

Enumerable#detectfinds and returns one item in your collection It takes a function as

an argument (one that returns trueor false) and will return the first item in the

collec-tion that causes the funccollec-tion to returntrue

function isEven(number) {

return number % 2 == 0;

}

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].detect(isEven);

//-> 2

If there are no matches,detectwill returnfalse

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

TỪ KHÓA LIÊN QUAN