Raghavendra
Raghavendra

Reputation: 5387

Confusion with Prototype in JavaScript

1.

I read Douglas Crockford's JavaScript Good Parts book. In the book, method is added to Function.prototype

a.

Function.prototype.method = function() {}

Function.prototype.method === Function.method; // true

b.

function MyClass() {}

MyClass.prototype.method = function() {}

MyClass.prototype.method == MyClass.method // false

infact MyClass.method is undefined.

Why is it true in step a and false in step b?

2.

please explain the following:

Object instanceof Function    // true
Function instanceof Object    // true
Object instanceof Object      // true
Function instanceof Function  // true

It is very confusing. please explain in simple words.

Upvotes: 3

Views: 82

Answers (2)

Ben Aston
Ben Aston

Reputation: 55729

1a.

01 Function.prototype.method = function foo() {}
02 Function.prototype.method === Function.method; // true

This is the addition of a property to the object pointed to by the prototype property of the built-in Function function-object.

Function is a built-in function-object instance named "Function". Function is therefore an object because functions are objects. Because Function is a function, it has a prototype property. In this case, it is another function-object.

Line 1 above adds a property named method to Function.prototype pointing it to the function-object foo (named for clarity).

Line 2 performs a test for reference equality between Function.prototype.method (created in line 1) and the result of attempting to get the value associated with the property method on the built-in Function function-object. Property resolution in JavaScript is performed by searching the chain of objects linked by the prototype-chain.

So in line 2 Function.prototype.method finds the property immediately as the method property is located directly on Function.prototype.

Also on line 2, Function.method is not found immediately on Function; the search then continues by looking at what is pointed at by the Function.__proto__ property (this is known as the prototype chain). The __proto__ reference in JavaScript automatically points to the prototype property of the function that created it. In this case, because we are at the top of the prototype chain (this is the top-most function!), we have the unusual situation where the built-in Function "created itself" (in reality Function was created by the runtime itself, outside of userland code), meaning that both the prototype and __proto__ properties - in this instance - point to the same object.

So the search for method follows the __proto__ link, finds the same object pointed to by Function.prototype, and finds a property method there. Hence:

02 Function.prototype.method === Function.method; // true

1b.

01 function MyClass() {}    
02 MyClass.prototype.method = function foo() {} // Named for clarity.
03 MyClass.prototype.method == MyClass.method // false 
04 // infact MyClass.method is undefined.

This is normal userland code and we do not have the same problem of having to find the prototype for the top-most Function object as in 1a.

As soon as it is declared (line 1 above), MyClass gets a prototype property like every function, pointing to an empty object instance.

Line 2 adds a property method to this empty object instance and points it to a function foo.

Line 3 tests for reference equality between foo and the result of looking for a property method on MyClass. As before, to find method on MyClass a search is performed. It does not exist directly on MyClass, so the object located on the property __proto__ is checked for a property named method (again, this is the prototype chain being traversed). In this case, just like 1a (and as for every object in JavaScript), the __proto__ points to the prototype property of the function that created the object. Function-object MyClass was created by the built-in Function function-object, thus MyClass.__proto__ points to Function.prototype (note, not MyClass.prototype). It finds nothing there and continues the search up the prototype chain. It ultimately fails to find a property called method, so returns undefined.

Hence:

MyClass.prototype.method == MyClass.method // false

2.

Object instanceof Function    // true

Object is a built-in constructor function-object for creating objects. Hence it is a function.


Function instanceof Object    // true

instanceof is an operator that returns true if the prototype property of the RHS object resides on the prototype chain of the LHS. The prototype chain of Function is:

Function.__proto__ -> Function.prototype
Function.prototype -> function f() {} // An ordinary function, named for clarity
f.__proto__ -> {} // An ordinary object. Let's call it 'o'.

So at the top of the prototype chain for functions, in order to avoid a circular loop, the prototype of the Object constructor function is used as f.__proto__ (I call it f here for clarity). Hence:

Function instanceof Object    // true

Object instanceof Object      // true

For this to be true Object.prototype must be on the prototype chain of Object.

Object.__proto__ -> Function.prototype 
Function.prototype.__proto__ -> {} // This is 'o' from above.

So Function.prototype.__proto__ === Object.prototype, hence:

Object instanceof Object      // true

Function instanceof Function  // true

This is true for the same explanation as 1a.

Upvotes: 1

Travis J
Travis J

Reputation: 82267

1.

a) You have just extended the Function built in object and now every instance of Function has that property attached, including the Function built in instance.

b) You have just extended MyClass with method and now every instance of MyClass has that method attached. However, MyClass is not an instance of MyClass and as a result that method is not present.

2.

These are standard built-in objects in the language. They are instances which can return an instance. With regards to Object, its prototype is shared with everything because everything derives from Object - it is best in general to avoid changing its prototype.

So that is why it seems that Function is an instance of Object. Everything is. Every instance derives from Function, so the Object instance is also an instance of Function. And that is the reverse.

There is a whole set of other fundamental objects, Object will not be an instance of Number for example, but Number is an instance of both Object and Function.

More on this list can be found at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects

Shown below is only a small subset of these objects as the list contained some objects which are more than likely not of interest (such as URIError).

  • Object
  • Function
  • Boolean
  • Symbol
  • Error
  • Number
  • Math
  • Date
  • String
  • RegExp
  • Array
  • JSON
  • Promise

Upvotes: 4

Related Questions