17. Extending Built-in Objects


In This Chapter

Extend your objects’ functionality

Learn more about the prototype chain


As you know very well by now, JavaScript comes from the factory with a good supply of built-in objects. These objects provide some of the core functionality for working with text, numbers, collections of data, dates, and a whole lot more. As you become more familiar with JavaScript and start doing interesting-er and cleverer things, you’ll often find that you want to do more and go farther than what the built-in objects allow.

Let’s take a look at an example of when something like this might occur. Below is an example of how you can shuffle the contents of an array:

function shuffle(input) {
    for (var i = input.length - 1; i >= 0; i--) {

        var randomIndex = Math.floor(Math.random() * (i + 1));
        var itemAtIndex = input[randomIndex];

        input[randomIndex] = input[i];
        input[i] = itemAtIndex;
    }
    return input;
}

The way you use this shuffle function is by simply calling it and passing in the array whose contents you want shuffled:

var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
shuffle(tempArray);

// and the result is...
alert(tempArray);

After this code has run, the end result is that the contents of your array are now rearranged. Now, this functionality is pretty useful. I would say this is sooo useful, the shuffling ability should be a part of the Array object and be as easily accessible as push, pop, slice, and other doo-dads the Array object has.

If the shuffle function were a part of the Array object, you could simply use it as follows:

var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
tempArray.shuffle();

This is an example of us extending a built-in object (the Array) with some functionality that we defined (the shuffle). In this chapter, we are going to look at how exactly to accomplish this, why it all works, and why extending built-in objects is pretty controversial.

Onwards!

Say Hello to Prototype...Again—Sort of!

Extending a built-in object with new functionality sounds complicated, but it is really simple once you understand what needs to be done. To help with this, we are going to look at a combination of sample code and diagrams all involving the very friendly Array object:

Image

Um...anyway, let’s say that we have the following code:

var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

If we were to diagram the full hierarchy of the tempArray object, it would look as follows:

Image

On the left, we have our tempArray object that is an instance of Array. The built-in Array object is derived from the basic Object type. Now, what we want to do is extend the Array object with our shuffle function. What this means is that we need to figure out a way to get our shuffle function inserted into our Array object itself:

Image

Here is the part where the quirkiness of JavaScript shines through. We don’t have access to the Array object source code. We can’t find the function or object that makes up the Array and insert our shuffle function into it like we might for a custom object that we defined. Your built-in objects, such as the Array, are defined deep inside your browser’s volcanic underbelly where no human being can go. We need to take another approach.

That another approach involves casually sneaking in and attaching your functionality by using the Array object’s prototype property. That would look something like this:

Array.prototype.shuffle = function () {

    var input = this;

    for (var i = input.length - 1; i >= 0; i--) {

        var randomIndex = Math.floor(Math.random() * (i + 1));
        var itemAtIndex = input[randomIndex];

        input[randomIndex] = input[i];
        input[i] = itemAtIndex;
    }
    return input;
}

Notice that our shuffle function is declared on Array.prototype! As part of this attachment, we made a minor change to how the function works. The function no longer takes an argument for referencing the array you need shuffled:

function shuffle(input) {
     .
     .
     .
     .
     .
}

Instead, because this function is now a part of the Array object, the this keyword inside the function body points to the array that needs shuffling:

Array.prototype.shuffle = function () {
    var input = this;
     .
     .
     .
     .
}

Taking a step back, once you run this code, your shuffle function will find itself shoulder to shoulder with all of the other built-in methods the Array object provides:

Image

If you wanted to access the shuffle property (err...method...I gotta stop doing that!), you can now do so using the approach we had initially desired:

var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
tempArray.shuffle();

This is because the prototype property provides you with direct access to your Array object’s insides. Declaring the shuffle function on it gave us the result we wanted. Best of all, any new arrays you create will also have access to the shuffle functionality by default thanks to how prototype inheritance works.

Extending Built-in Objects Is Controversial

Given how easy it is to extend a built-in object’s functionality by declaring methods and properties using the prototype object, it’s easy to think that everybody loves the ability to do all of this. As it turns out, extending built-in objects is a bit controversial. The reasons for this controversy revolve around the fact that...

You Don’t Control the Built-in Object’s Future

There is nothing preventing a future implementation of JavaScript from including its own version of shuffle that applies to Array objects. At this point, you have a collision where your version of shuffle and the browser’s version of shuffle are in conflict with each other - especially if their behavior or performance characteristics wildly differ. Rut ruh!

Some Functionality Should Not Be Extended or Overridden

Nothing prevents you from using what you’ve learned here to modify the behavior of existing methods and properties. For example, this is me changing how the slice behavior works:

Array.prototype.slice = function () {
    var input = this;
    input[0] = "This is an awesome example!";

    return input;
}

var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
tempArray.slice();

// and the result is...
alert(tempArray);

While this is a terrible example, this does show how easy it was for me to break existing functionality.


Image Tip

Just a quick reminder for those of you reading these words in the print or e-book edition of this book: If you go to www.quepublishing.com and register this book, you can receive free access to an online Web Edition that not only contains the complete text of this book but also features a short, fun interactive quiz to test your understanding of the chapter you just read.

If you’re reading these words in the Web Edition already and want to try your hand at the quiz, then you’re in luck – all you need to do is scroll down!


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.78.136