It’s a well known thing that JavaScript does not have classes and regular object oriented features like we are used to to from languages like C# and Java.

Instead, in JavaScript each object is an extension of another object called it’s prototype. Each object has exactly one reference to a prototype object. This reference may also be null, which is the case eventually for all chains of prototype references.

For example, using Google’s Chrome browser I got this prototype chain for a commong String:

var str = "hello";

“hello” : String –> “” : String –> {} : Object –> null

1. First off, str is a reference to a String object, containing the primitive string value “hello”.
2. This String object has a prototype, which is another String object. However this String object is an empty string.
3. The empty String has a prototype, which is an empty Object (called the standard built-in Object prototype object).
4. The empty Object’s prototype is the primitive value null.

 

The way JavaScript resolves property accesses, functions and the like is by first searching in the object you are referencing. If not there then the prototype object is searched. It continues like this all the way until it reaches the “null” prototype reference (like we saw for the string object).

 

So an important difference between regular object orientation and prototype-based inheritance is that the prototype is always a separate object instance.

Now, if you create a new object but do not explictly set it’s prototype, then the “standard built-in Object prototype object” is used. This can have some odd consequences..

 

Since the same object is used for default prototypes all through JavaScript, what happens if you add something to this standard built-in Object prototype object ? It should appear everywhere right ? 

 

I did some testing using the debugger in Chrome:
Let a be a new object by using object literal notation. It does not have a test() function yet:

var a = {};
a.test();
>>> TypeError: undefined is not a function

Now, add a silly test function to a’s prototype:

a.__proto__.test = function () { return "xyzzyx"; }
a.test();
>>> "xyzzyx"

However, “b” also gets the same standard object prototype, and therefore the same test() function as “a”:

var b = new Object();
b.test();
>>> "xyzzyx"
var c = "another string";
c.test()
>>> "xyzzyx"   // oops, seems it's contagious..

Even the global object will have the test() function through it’s prototype:

test();
>>> "xyzzyx"

Prototype-based inheritance is a strange and different world as compared to regular object orientation.

Advertisements