Loan i Loan u Home e Improvement n Business ssearch; Loan & Small b
Bestforexsite Business osearche Www Improvement l Loan q Business o Small tsearchi& Business d Improvement u Loan ; General C Www a Small g General s Www a searchu Loan i Small essearch h searche Bestforexsite tosearchesearchs Loan t
ssearcha Www cbsearchs General a
csearchcsearche Bestforexsite r Improvement h Improvement ssearchach Loan s
asearchchsearch Home wsearch Www
function displayQuote() {}
var williamShakespeare = {};
var markTwain = {};
var oscarWilde = {};
williamShakespeare.sayIt(); // true, true
markTwain.sayIt(); // he didn’t know where to play golf
// watch this, each function has a method call()
// that allows the function to be called as a
// method of the object passed to call() as an
// argument.
// this line below is equivalent to assigning
// displayQuote to sayIt, and calling oscarWilde.sayIt().
displayQuote.call(oscarWilde); // ouch!
The last line in Figure 2 shows an alternative way of calling a function as a method of an object. Remember, a function in JavaScript is an object. Every function object has a method named call, which calls the function as a method of the first argument. That is, whichever object we pass into call as its first argument will become the value of "this" in the function invocation. This will be a useful technique for calling the base class constructor, as we’ll see later.
One thing to remember is never to call functions that contain "this" without an owning object. If you do, you will be trampling over the global namespace, because in that call, "this" will refer to the Global object, and that can really wreak havoc in your application. For example, below is a script that changes the behavior of JavaScript’s global function isNaN. Definitely not recommended!
alert("NaN is NaN: " + isNaN(NaN));
function x() {};
}
// alert!!! trampling the Global object!!!
x();
alert("NaN is NaN: " + isNaN(NaN));
So we’ve seen ways to create an object, complete with its properties and methods. But if you notice all the snippets above, the properties and methods are hardcoded within the object definition itself. What if you need more control over the object creation? For example, you may need to calculate the values of the object’s properties based on some parameters. Or you may need to initialize the object’s properties to the values that you’ll only have at run time. Or you may need to create more than one instance of the object, which is a very common requirement.
In C#, we use classes to instantiate object instances. But JavaScript is different since it doesn’t have classes. Instead, as you’ll see in the next section, you take advantage of the fact that functions act as constructors when used together with the "new" operator.
The strangest thing about JavaScript OOP is that, as noted, JavaScript doesn’t have classes like C# or C++ does. In C#, when you do something like this:
Dog spot = new Dog();
you get back an object, which is an instance of the class Dog. But in JavaScript there’s no class to begin with. This closest you can get to a class is by defining a constructor function like this:
function DogConstructor(name) {}
};
}
var spot = new DogConstructor("Spot");
spot.respondTo("Rover"); // nope
spot.respondTo("Spot"); // yeah!
OK, so what’s happening here? Ignore the DogConstructor function definition for a moment and examine this line:
var spot = new DogConstructor("Spot");
What the "new" operator does is simple. First, it creates a new empty object. Then, the function call that immediately follows is executed, with the new empty object set as the value of "this" within that function. In other words, the line above with the "new" operator can be thought of as similar to the two lines below:
// create an empty object
var spot = {};
// call the function as a method of the empty object
DogConstructor.call(spot, "Spot");
As you can see in the body of DogConstructor, invoking this function initializes the object to which the keyword "this" refers during that invocation. This way, you have a way of creating a template for objects! Whenever you need to create a similar object, you call "new" together with the constructor function, and you get back a fully initialized object as a result. Sounds very similar to a class, doesn’t it? In fact, usually in JavaScript the name of the constructor function is the name of the class you’re simulating, so in the example above you can just name the constructor function Dog:
// Think of this as class Dog
function Dog(name) {}
};
}
var spot = new Dog("Spot");
In the Dog definition above, I defined an instance variable called name. Every object that is created using Dog as its constructor function will have its own copy of the instance variable name (which, as noted earlier, is just an entry into the object’s dictionary). This is expected; after all, each object does need its own copies of instance variables to carry its state. But if you look at the next line, every instance of Dog also has its own copy of the respondTo method, which is a waste; you only need one instance of respondTo to be shared among Dog instances! You can work around the problem by taking the definition of respondTo outside Dog, like this:
function respondTo() {}
function Dog(name) {}
This way, all instances of Dog (that is, all instances created with the constructor function Dog) can share just one instance of the method respondTo. But as the number of methods grow, this becomes harder and harder to maintain. You end up with a lot of global functions in your codebase, and things only get worse as you have more and more "classes," especially if their methods have similar names. There’s a better way to achieve this using the prototype objects, which are the topic of the next section.
The prototype object is a central concept in object-oriented programming with JavaScript. The name comes from the idea that in JavaScript, an object is created as a copy of an existing example (that is, a prototype) object. Any properties and methods of this prototype object will appear as properties and methods of the objects created from that prototype’s constructor. You can say that these objects inherit their properties and methods from their prototype. When you create a new Dog object like this
var buddy = new Dog("Buddy");
the object referenced by buddy inherits properties and methods from its prototype, although it’s probably not obvious from just that one line where the prototype comes from. The prototype of the object buddy comes from a property of the constructor function (which, in this case, is the function Dog).
In JavaScript, every function has a property named "prototype" that refers to a prototype object. This prototype object in turn has a property named "constructor," which refers back to the function itself. It’s sort of a circular reference; Figure 3 illustrates this cyclic relationship better.
Figure 3 Every Function’s Prototype Has a Constructor Property
Now, when a function (in the example above, Dog) is used to create an object with the "new" operator, the resulting object will inherit the properties of Dog.prototype. In Figure 3, you can see that the Dog.prototype object has a constructor property that points back to the Dog function. Consequently, every Dog object (that inherits from Dog.prototype) will also appear to have a constructor property that points back to the Dog function. The code in Figure 4 confirms this. This relationship between constructor function, prototype object, and the object created with them is depicted in Figure 5.
Figure 4 Objects Appear to Have Their Prototype’s Properties
var spot = new Dog("Spot");
// Dog.prototype is the prototype of spot
alert(Dog.prototype.isPrototypeOf(spot));
// spot inherits the constructor property
// from Dog.prototype
alert(spot.constructor == Dog.prototype.constructor);
alert(spot.constructor == Dog);
// But constructor property doesn’t belong
// to spot. The line below displays "false"
alert(spot.hasOwnProperty("constructor"));
// The constructor property belongs to Dog.prototype
// The line below displays "true"
alert(Dog.prototype.hasOwnProperty("constructor"));
Figure 5 Instances Inherit from Their Prototype
Some of you may have noticed the calls to hasOwnProperty and isPrototypeOf method in Figure 4. Where do these methods come from? They don’t come from Dog.prototype. In fact, there are other methods like toString, toLocaleString, and valueOf that we can call on Dog.prototype and instances of Dog, but which don’t come from Dog.prototype at all. It turns out that just like the .NET Framework has System.Object, which serves as the ultimate base class for all classes, JavaScript has Object.prototype, which is the ultimate base prototype for all prototypes. (The prototype of Object.prototype is null.)
In this example, remember that Dog.prototype is an object. It is created with a call to the Object constructor function, although it is not visible:
Dog.prototype = new Object();
So just like instances of Dog inherit from Dog.prototype, Dog.prototype inherits from Object.prototype. This makes all instances of Dog inherit Object.prototype’s methods and properties as well.
Every JavaScript object inherits a chain of prototypes, all of which terminate with Object.prototype. Note that this inheritance you’ve seen so far is inheritance between live objects. It is different from your usual notion of inheritance, which happens between classes when they are declared. Consequently, JavaScript inheritance is much more dynamic. It is done using a simple algorithm, as follows: when you try to access a property/method of an object, JavaScript checks if that property/method is defined in that object. If not, then the object’s prototype will be checked. If not, then that object’s prototype’s prototype will be checked, and so on, all the way to Object.prototype. Figure 6 illustrates this resolution process.
Figure 6 Resolving toString() Method in the Prototype Chain (Click the image for a larger view)
The way JavaScript resolves properties access and method calls dynamically has some consequences:Changes made to a prototype object are immediately visible to the objects that inherit from it, even after these objects are created.If you define a property/method X in an object, a property/method of the same name will be hidden in that object’s prototype. For instance, you can override Object.prototype’s toString method by defining a toString method in Dog.prototype.Changes only go in one direction, from prototype to its derived objects, but not vice versa.
Figure 7 illustrates these consequences. Figure 7 also shows how to solve the problem of unnecessary method instances as encountered earlier. Instead of having a separate instance of a function object for every object, you can make the objects share the method by putting it inside the prototype. In this example, the getBreed method is shared by rover and spot—until you override the toString method in spot, anyway. After that, spot has its own version of the getBreed method, but the rover object and subsequent objects created with new GreatDane will still share that one instance of the getBreed method defined in the GreatDane.prototype object.
Figure 7 Inheriting from a Prototype
function GreatDane() {}
var rover = new GreatDane();
var spot = new GreatDane();
GreatDane.prototype.getBreed = function() {};
// Works, even though at this point
// rover and spot are already created.
alert(rover.getBreed());
// this hides getBreed() in GreatDane.prototype
spot.getBreed = function() {};
alert(spot.getBreed());
// but of course, the change to getBreed
// doesn’t propagate back to GreatDane.prototype
// and other objects inheriting from it,
// it only happens in the spot object
alert(rover.getBreed());
Sometimes you need properties or methods that are tied to classes instead of instances—that is, static properties and methods. JavaScript makes this easy, since functions are objects whose properties and methods can be set as desired. Since a constructor function represents a class in JavaScript, you can add static methods and properties to a class simply by setting them in the constructor function like this:
function DateTime() {}
// set static method now()
DateTime.now = function() {};
alert(DateTime.now());