JavaScript: Object inheriting from Function.prototype

I have tested James Shore Object Playground and I can see that all methods inherit from Function.prototype, including methods on the global Object.prototype. How it works? Isn't that a cool circular? I mean ... isn't Function.prototype "itself" an Object.prototype object? So how does Object have something of Function.prototype? Isn't just a subtype of an object a function? Should the object essentially contain these behaviors anyway? Why is this inheritance necessary?

enter image description here

+3


source to share


2 answers


TL; DR

Object.prototype is the last in the prototype chain and it doesn't inherit anything. The Object constructor is the one that inherits from Function.prototype , because it's just a function; this is a function instance.


Long version

Since your question is a general one, I will try to cover several topics and hopefully you will answer your own question. Here are the topics I'll try to describe:

  • Two ways to use the word "prototype".
  • How classes are created in JavaScript.
  • How Function and Object constructors are related .

Note. ... It can be difficult and confusing at times to explain how JavaScript works. I hope you get something out of this though.


Two ways to use the word "prototype"

The word "prototype" can be a little confusing in JavaScript. This is because there are at least two ways to use this word depending on the context:

1) "Object prototype another object

Another object's prototype object is also referred to as an "internal prototype", denoted as [[Prototype]] or __proto__

; they all mean the same thing. For example, consider the array: nums = [9, 8, 7];

. We say that it nums

is an array ... but why?

  • We say it's an array because it's a constructor instance Array

    (constructors are just functions, except we use them with the new keyword ).
  • We also say that it is an array because its prototype object (internal prototype aka) is an object contained within a property Array.prototype

    .

2) "Property of the prototype of the constructor function"

Continuing the example of the array nums

, Array constructor function has a property with the name prototype

, and we can access it as follows: Array.prototype

. This property is an "internal prototype" Array instances and provides all the methods that we use to call arrays - such as forEach

, push

, pop

, join

etc.

So, along the same lines, the internal prototype of my function foo()

or any other function is an object that is contained within a property Function.prototype

; in other words, Function.prototype

it is any "internal prototype" function of an object. In addition, the Function constructor can be said to have a prototype property, which is ultimately the "internal prototype" of all functions.

Where do I get what we are talking about one thing (prototype) in two different ways. In the first case, we say: "prototype / internal prototype" of the object, and in the second - "constructor prototype property".


How classes are created in JavaScript

In JavaScript , constructor functions are similar to classes in other programming languages. Well, not quite. In fact, to resemble classes, JavaScript uses a combination of a constructor function and another object called a prototype... In fact, every JavaScript function automatically acquires a prototype property because a function can be used as a constructor or simply as a function. When a function is not used as a constructor, its prototype property is not used for anything, and it just dangles there like a useless property.

In classical languages, a class contains both instance variables and instance methods; however, in JavaScript, a constructor function contains instance variables, and a prototype object contains instance methods.



Instance variables are unique to a specific instance of a constructor function (they contain specific instance data), and instance methods are shared by all instances. In other words, all instances can execute instance methods, but cannot access variables from each other.

Thus, all objects in JavaScript are instances of their corresponding constructor functions. For example, an array such as [1,2,3]

is a constructor instance function Array() {}

. Objects like {key: 'value'}

are constructor instances function Object() {}

. JavaScript functions like alert()

are constructor instances function Function() {}

... etc.

Again, all constructor functions in JavaScript have a property prototype

, and this property includes methods that inherit constructor instances.

Example:

// Person constructor to create people instances
function Person(name, age) {
  // Every instance has its own "instance variables", a.k.a. properties. 
  this.name = name;
  this.age  = age;
}


// The "instance methods"
Person.prototype = {
  greet: function() {
    return 'Hello ' + this.name;
  },
  //...
};


// Joe is an instance of the `Person` constructor, and Joe "prototype"
// is the `Person.prototype` object. We call Joe "prototype" the 
// "internal prototype". 
var joe = new Person('Joe Doe', 44);
joe.name; //=> Joe Doe
joe.greet(); //=> Hello Joe Doe

      


How function and object constructors are related

Constructor Object

.

The Object constructor is similar to the Person constructor above, except that it creates instance instances instead of user instances.

Constructor Function

.

The Function constructor is similar to the Person and Object constructors above, except that it creates Function instances, in other words, it creates functions.

All constructors in JavaScript, such as Person

, Object

, Array

, Function

, String

, Boolean

, etc., are merely functions. Since they are functions, this means that they were created from new Function

internally in the language, and all functional methods such as call()

and apply()

refer to Function.prototype . In other words, Function.prototype is the prototype / internal prototype object of all functions, including constructors and the function itself Function

.

Output:

Do not confuse the constructor property prototype

, which includes methods that future instances will use, with the internal prototype of the constructor itself.

However, keep in mind that a constructor property prototype

is internal [[Prototype]] instances of that constructor. For example, Function.prototype

[[Prototype]] is internal to a constructor Object

, which makes sense, since a constructor Object

is another function (instance Function

).

For code output, take a look at how the Object and Function constructors are created inside JavaScript:

// Object constructor
// ==============================================
function Object() { /* ... */ }
// Object.keys()
// Object.observe()
// ...


// `Object.__proto__` (internal [[Prototype]])
// -----------------------------------------------
// Since `Object` is a function, it inherits all of Function 
// instance methods (the ones inside of Function.prototype). 
// 
// In other words the `Object` constructor can use methods 
// like `apply()`, `call()`, `bind()`, and more.
// 
// So we can say that the Object prototype is the 
// `Function.prototype` object.
Object.__proto__ = Function.prototype;


// `Object.prototype` (instance methods)
// -----------------------------------------------
// The Object `prototype` property is totally different from  
// the `__proto__` property. This `prototype` property includes 
// methods that all JavaScript objects inherit. So an object
// literal like `var obj = {}` or an array like `var arr = []` 
// or even a function like `alert` can use these methods.
Object.prototype = {
  constructor: Object,
  hasOwnProperty: function() {},
  isPrototypeOf: function() {},
  //...
};



// Function constructor
// ==============================================
function Function() { /* ... */ }
// Function.call()
// Function.apply()
// ...


// [[Prototype]]  +  instance methods
// -----------------------------------------------
// Since `Function` is a function itself and at the same time 
// the constructor for other JavaScript functions, its internal
// [[Prototype]] and the `prototype` property point to the same 
// exact object.
Function.__proto__ = Function.prototype = {
  apply: function() {},
  call: function() {},
  bind: function() {},

  //...

  // Just an object literal, so it inherits the 
  // Object instance methods.
  __proto__: Object.prototype
};

      


Additional Resources

+2


source


What are prototypes?

JavaScript is a prototype-based language. This means there are technically no "classes". There are only prototypes that describe objects. Every object has a prototype. The prototype itself is actually an object. (Confused, huh? Don't think too hard about it, if you can't wrap it around you, it will click someday. Just know that prototypes are objects that you can change).

Before proceeding, I would like to point out that my code examples here are not following good or best practices. The code samples I've written are purely a demonstration or explanation of the concept.

Let's look at some code:

Object.toString();                 // "[object Object]"
Object.prototype.toString();       // "[object Object]"
Object.hasOwnProperty('toString'); // true
typeof Object;                     // "function"
typeof Object.prototype            // "object"

var obj = new Object();
obj.toString();                    // "[object Object]"
obj.hasOwnProperty('toString');    // false

obj.toString = function() {
    return 'My Object';
};

obj.toString();                    // "My Object"
obj.hasOwnProperty('toString')     // true
obj.__proto__.toString();          // "[object Object]"
typeof obj;                        // "object"
typeof obj.__proto__;              // "object"

      

You may have also noticed what typeof Object

returns "function"

. This is because Object is actually a constructor method to create new objects. My object instance is actually typeof obj === "object"

.

Prototype chain

As you can see in the above code, Object

contains a method named toString

. But Object

there are no copies . obj

doesn't have a method of its own toString

. But you can still call toString

on obj

. JavaScript does inheritance by following the prototype chain.

I could overwrite obj.toString

to give obj

my own method toString

, but the property obj.__proto__

still has the original method toString

from it prototype

.

If the object in question does not contain its own property toString

, then the property will look at its prototype. If the native prototype does not contain a property toString

, then the search will continue the prototype chain until the property is found. If it is a prototype null

, then it is a property undefined

.

Is everything in JavaScript an object?

Yes, down at the very core, eventually in the prototype chain, every object is a JavaScript object. Including Functions

.

var func = function() {};
func.__proto__                       //function Empty() {}
func.__proto__.__proto__             // Object {}
func.__proto__.isPrototypeOf(Object) // true

      



Thus, a function is an object in JavaScript. This is why you can attach properties to functions.

And some clarifications ...

all methods inherit from Function.prototype

No, all methods do not inherit from Function

. Methods Function

.

So, how does Object.prototype have something of the .prototype function?

The object does not inherit anything from the function. An object can use a function, such as a method toString

.

Object

kinda showcases a composite design structure. (Except that you can add properties to an object that references itself and / or creates circular references)

From [ http://en.wikipedia.org/wiki/Composite_pattern ]

In software development, a composite pattern is a design pattern for partitions. The composite pattern specifies that a group of objects should be treated the same as a single instance of an object. The purpose of a composite is to "arrange" objects in tree structures to represent the hierarchy of the whole.

Because it Object

contains several properties that are also Object

.

Is this the hinge? No, not at all. But this is definitely recursive.

You can read more about JavaScript prototypes here: http://blog.pluralsight.com/understanding-javascript-prototypes

Note that ES6 introduces actual classes to JavaScript. This is different from everything I explained above. ES6 class

is something I haven't played with yet.

+1


source







All Articles