admin管理员组文章数量:1402800
I was testing out James Shore's Object Playground, and I see that all methods inherit from Function.prototype, including the methods on the global Object.prototype. How does that work? Isn't that kinda circular? I mean... doesn't the Function.prototype "itself" inherent from the Object.prototype? So how does Object inherent anything from Function.prototype? Isn't a function only a sub-type of Object? Shouldn't Object inherently contain these behaviors anyway? Why the need for that inheritance?
I was testing out James Shore's Object Playground, and I see that all methods inherit from Function.prototype, including the methods on the global Object.prototype. How does that work? Isn't that kinda circular? I mean... doesn't the Function.prototype "itself" inherent from the Object.prototype? So how does Object inherent anything from Function.prototype? Isn't a function only a sub-type of Object? Shouldn't Object inherently contain these behaviors anyway? Why the need for that inheritance?
Share Improve this question edited Apr 23, 2015 at 7:51 shmuli asked Apr 23, 2015 at 3:22 shmulishmuli 5,1926 gold badges35 silver badges64 bronze badges2 Answers
Reset to default 8TL;DR
Object.prototype is last in the prototype chain and it doesn't inherit from anything. The Object constructor is the one that inherits from Function.prototype because it's just a function; it's a Function instance.
Long Version
Since your question is a general one, I'll try to describe a few subjects and hopefully you will answer your own question. Here are the subjects I'll try to cover:
- Two ways to use the word "prototype".
- How classes are created in JavaScript.
- How the Function & Object constructors relate.
Note: It can be hard and at times confusing to explain how JavaScript really works. I hope that you'll get something out of it though.
Two ways to use the word "prototype"
The word "prototype" can be a little confusing in JavaScript. That's because there are at least two ways to use this word depending on the context:
1) "The prototype object of another object"
The prototype object of another object is also talked about as the "internal prototype", denoted as [[Prototype]], or __proto__
; they all mean the same thing. As an example let's take this array: nums = [9, 8, 7];
. We say that nums
is an array... but why?
- We say it's an array because it is an instance of the
Array
constructor (constructors are just functions, except we use them with the new keyword). - We also say it's an array because its prototype object (a.k.a. "internal prototype") is the object contained inside of the
Array.prototype
property.
2) "The prototype property of a constructor function"
Continuing with the nums
array example, the Array constructor function has a property named prototype
, and we can access it like this: Array.prototype
. This property is the "internal prototype" of Array instances, and provides all the methods that we're used to calling on arrays - e.g. forEach
, push
, pop
, join
, and so on.
So, along the same lines, the internal prototype of my function foo()
, or any other function, is the object that's contained inside of the Function.prototype
property; in other words, Function.prototype
is any function's "internal prototype" object. Also, we can say that the Function constructor has a prototype property, which eventually is the "internal prototype" of all functions.
Where I'm getting at is that we speak of one thing (the prototype) in two different ways. In the first way we say: "the prototype/internal prototype" of an object, and in the second way we say: "the constructor's prototype" property.
How classes are created in JavaScript
In JavaScript constructor functions are like classes in other programming languages. Well, not quite. Actually, to resemble classes, JavaScript uses a bination of a constructor function and another object called the prototype. Actually every JavaScript function acquires a prototype property automatically because a function can be used as a constructor or simply as a function. When a function isn't used as a constructor, its prototype property isn't used for anything and it's just dangling there as a useless property.
In classical languages, the class contains both the instance variables and the instance methods, however in JavaScript, the constructor function contains the instance variables and its prototype object contains the instance methods.
Instance variables are unique to the particular instance of a constructor function (they contain instance specific data), and instance methods are shared by all instances. In other words, all instances can execute the instance methods but cannot access the variables of each other.
So, all objects in JavaScript are instances of their respective constructor functions. For example, an array such as [1,2,3]
is an instance of the function Array() {}
constructor. Objects such as {key: 'value'}
are instances of the function Object() {}
constructor. JavaScript functions such as alert()
are instances of the function Function() {}
constructor... and so on.
Again, all constructor functions in JavaScript have a prototype
property, and this property includes the methods that instances of the constructor will inherit.
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's "prototype"
// is the `Person.prototype` object. We call Joe's "prototype" the
// "internal prototype".
var joe = new Person('Joe Doe', 44);
joe.name; //=> Joe Doe
joe.greet(); //=> Hello Joe Doe
How the Function & Object constructors relate
The Object
Constructor.
The Object constructor is just like the Person constructor above, except it creates object instances instead of person instances.
The Function
Constructor.
The Function constructor is just like the Person & Object constructors above, except that it creates Function instances, in other words it creates functions.
All constructors in JavaScript like Person
, Object
, Array
, Function
, String
, Boolean
, and so on, are just functions. Since they are functions, it means that they were created with new Function
internally in the language, and all function methods like call()
and apply()
e from Function.prototype. In other words, Function.prototype is the "prototype/internal prototype" object of all functions, including constructors and the function Function
itself.
Conclusion:
Don't confuse a constructor's prototype
property, which includes the methods that future instances will use, with the internal prototype of the constructor itself.
However, keep in mind that a constructor's prototype
property is the internal [[Prototype]] of that constructor's instances. For example, Function.prototype
is the internal [[Prototype]] for the Object
constructor, and that makes sense since the Object
constructor is just another function (a Function
instance).
For a code conclusion take a look at how the Object & Function constructors are created internally in JavaScript:
// Object constructor
// ==============================================
function Object() { /* ... */ }
// Object.keys()
// Object.observe()
// ...
// `Object.__proto__` (internal [[Prototype]])
// -----------------------------------------------
// Since `Object` is a function, it inherits all of Function's
// 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's prototype is the
// `Function.prototype` object.
Object.__proto__ = Function.prototype;
// `Object.prototype` (instance methods)
// -----------------------------------------------
// The Object's `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's instance methods.
__proto__: Object.prototype
};
Further Resources
- https://developer.mozilla/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Determining_instance_relationships
- https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
- https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
- https://es5.github.io/#x15.3.4
- http://people.mozilla/~jorendorff/es5.1-final.html#sec-15.3.2.1; A prototype property is automatically created for every function, to provide for the possibility that the function will be used as a constructor.
- https://www.quora./In-JavaScript-what-is-the-logic-behind-the-data-structure-of-function-prototype-proto-and-constructor?share=1
What are Prototypes?
JavaScript is a prototype-based language. Which means that technically there are no "classes". There are just prototypes, which describes objects. Every object has a prototype. The prototype itself, is in fact an object. (Confusing huh? Don't think too hard about it, if you can't wrap your head around it. It will click sometime. Just know that prototypes are objects that you can modify).
Before we continue, I'd like to note that my code samples here does not follow proper or best practices. The code samples I have written is purely to demonstrate or to explain a 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 that typeof Object
returns "function"
. This is because Object is actually a constructor method, to instantiate new objects. My instance object is actually typeof obj === "object"
.
The Prototype Chain
As you see in the above code, Object
contains a method named toString
. But instances of Object
does not. obj
does not have its own toString
method. But you can still call toString
on obj
. JavaScript does its inheritance by following its prototype chain.
I could overwrite obj.toString
to give obj
its own toString
method, but obj.__proto__
property still have the original toString
method from its prototype
.
If the object in question does not contain its own property toString
, then the property will look at its prototype. If its own prototype does not contain the property toString
, then the lookup will continue up the prototype chain until the property is found. If the prototype is null
, then that is when a property is undefined
.
Everything in JavaScript is 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
So a function is an object in JavaScript. That is why you can attach properties to functions.
And some clarification...
all methods inherit from Function.prototype
No, all methods do not inherit from Function
. Methods are Function
.
So how does Object.prototype inherent anything from Function.prototype?
Object does not inherit anything from Function. Object may use Function, e.g the toString
method.
The Object
kinda demonstrates the posite design pattern. (With the exception that it is possible to add properties to an object that reference itself and/or create circular references)
From [ http://en.wikipedia/wiki/Composite_pattern ]
In software engineering, the posite pattern is a partitioning design pattern. The posite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a posite is to "pose" objects into tree structures to represent part-whole hierarchies.
Because Object
contains several properties, which are all also Object
.
So is it loopy? No, not really. But it definitely is recursive.
You can read more about JavaScript prototypes here: http://blog.pluralsight./understanding-javascript-prototypes
Note that ES6 is introducing actual classes in JavaScript. That is different from everything I explained above. ES6 class
is something I have not yet played around with.
本文标签: inheritanceJavaScript Object inheriting from FunctionprototypeStack Overflow
版权声明:本文标题:inheritance - JavaScript: Object inheriting from Function.prototype - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744354972a2602259.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论