I read an article which explains what prototype chain is.
It says that if I try to access an object's property but it doesn't have it, javascript engine will try it's .constructor.propotype. If it doesn't have it either then try .construtor.propotype.constructor.propotype. Untill it find the built-in Object().
But I test this:
function a() {}
b = new a();
then:
c = b.constructor.prototype
I get an empty a object.
then:
d = c.constructor.prototype
I get an empty a object.
It loops. No matter how many .constructor.prototype I call, it can't find Object(). What's wrong? Do I misunderstand the prototype chain?
In JS OOP the constructor and prototype properties are flaky, in that they aren't set for you when you perform inheritance. You are supposed to manually set/alter them to implement inheritance. See, for example, this tutorial.
It looks like the way you're trying to climb the prototype chain (by traversing through .constructor.prototype) never really reaches the Object top-level prototype, since when you have function a(){} the right constructor and prototype properties aren't set on a. I can't even manage to coerce them onto a; in Chrome I get:
> function a(){}
undefined
> a.constructor.prototype
function Empty() {}
> a.constructor.prototype = Object.prototype
Object
> a.constructor.prototype
function Empty() {} // hmmmm, the assignment didn't take...
Of course the runtime doesn't need to do this, since it has a reference to the actual prototype of each object. I.e. the language doesn't do the lookup via .constructor.prototype, it saves the prototype of each instance internally. So you can see how the lookup chain works if instead of .constructor.prototype you use .__proto__:
function a(){}
b = new a();
b.__proto__ === Object.prototype; // false
b.__proto__.__proto__ === Object.prototype; // true since we reached the top of the prototype chain
It is important to note that the property __proto__ has never been standard and in ES5 was standardised in a slightly different manner:
obj.__proto__ === Object.getPrototypeOf(obj);
This renders .__proto__ deprecated.
Looks like that I asked a stupid question.
if A is a function:
A.prototype.constructor === A
if A isn't a function:
A.prototype in a normal property.
So (in standard) there is no way to climb up the prototype chain.
Related
I am a beginner in Javascript and am learning about Object Oriented and prototyping in it.
As far as I know, Object is a function and is created by Function because Object.__proto__ === Function.prototype but looking through various diagrams online, I am quite confused by fact that How Function.prototype.__proto__ === Object.prototype.
What does Function.prototype.__proto__ mean?
Isn't it something that is developed by language owners as Function is the first thing from which everything arrives.
Then what does it mean? Am I lacking some important fact? I looked through other StackOverflow answers but can't find anything related to it.
TL;DR
__proto__ is a property of an object which enables you to look up in the prototype chain. While prototype is a property of a Function which enables you to add shareable functionalities to a constructor function.
Long Answer
Understand this from an example, let's say you create a constructor function.
function A() {} and then create an instance of it, var a = new A().
Then, add a function as following:
A.prototype.getA = function () { return 'A'; }.
Now, if you try to access a.getA(), you'll get the result, i.e. getA will be executed.
But how does it know about the function getA even though getA has been added after the instance a was created. It's because of using __proto__, you can traverse up in the chain (you must have heard about prototype chaining).
Technically, __proto__ is a property of an object, while prototype is a property of function. But how could functions have property? Because everything in JavaScript is converted implicitly to an object. Ever wondered how could you something like this: 'test'.toUpperCase()? Isn't string literals are 'not object' and they are primitives?
Read this for reference: http://jayendra.co.in/objects-in-javascript/
Now to answer your question:
What does Function.prototype.__proto__ mean?
You are trying to access the prototype property of Function constructor function. Remember, prototype itself is an object, so you can access properties like constructor and __proto__.
Function.prototype.__proto__ === Object.prototype
To enable chaining, when you access __proto__ property, you are looking up!
Any function can access all the properties of an object. How?
A property of Object, let's say toString. You can do, A.toString() // A created at the start. But we never created a function toString for A constructor function!
myFunc.prototype is the __proto__ of any object constructed by calling new myFunc().
Thinking in terms of classical (Java- or C++-style) OO, you could say that myFunc is a constructor and (therefore) myFunc.prototype is the class. In that sense, myFunc.prototype.__proto__ is the superclass; that is, the prototype of the prototype of all objects created with new myFunc.
One useful thing you can do to myFunc.prototype.__proto__ is assign to it to create a superclass relationship, e.g.
myFunc.prototype.__proto__ = mySuperclassConstructor.prototype
This idiom sheds light on why Function.prototype.__proto__ === Object.prototype holds (the core of your question): it simply means that Function is a subclass of Object — Or in other words, JavaScript runtimes do something equivalent to the above code snippet in their prelude so as to make Function a subclass of Object (as they should, per ECMA-262 §§ 19.2.2 and 19.2.3)
Careful though, while __proto__ happens to work on all modern (2019) JavaScript implementations (node.js and browsers), its use is both non-standard and slow. Consider using “real” ES6 classes instead.
Why the prototype of instance is not the same like the prototype of its constructor if to use the Object.getPrototypeOf() function?
function A(n){this.n=n;};
let a = new A(1);
console.log('Object.getPrototypeOf(a) == Object.getPrototypeOf(A); // ',
Object.getPrototypeOf(a) == Object.getPrototypeOf(A));
console.log('Object.getPrototypeOf(a) == A.prototype; // ',
Object.getPrototypeOf(a) == A.prototype);
Object.getPrototypeOf() returns the value of the internal [[Prototype]] property, which is not the same as the prototype property. When you create a function (or a class), it gets a prototype property, and when you create an instance of it, the created object has the internal [[Prototype]] property set to the prototype property of the class.
Your first example evaluates to false, because [[Prototype]] of a is A.prototype, but [[Prototype]] of A is Function.prototype, because every function is an instance of the Function class.
You are seeing this because A's prototype (the prototype object from which A is derived) is Function.prototype, not A.prototype:
function A(n){this.n=n;};
console.log('Object.getPrototypeOf(A) === Function.prototype');
console.log(Object.getPrototypeOf(A) === Function.prototype);
let a = new A(1);
console.log('Object.getPrototypeOf(a) === A.prototype');
console.log(Object.getPrototypeOf(a) === A.prototype);
Object.getPrototypeOf(x) is not just a convoluted way of writing x.prototype.
Object.getPrototypeOf(x) returns the prototype from which x is derived.
x.prototype is the prototype of objects created using x as a constructor.
Although it seems simple at a glance but the answer will become more clear if you know how protoypal inheritance works in JS.
Still I would try to explain it in short, how prototype works.
In JS, everything is an object. Although primitive values such as numbers, strings, boolean do not look like objects but are treated like objects internally.
For a quick reference see below. Everything is an object.
Now lets come to the case mentioned in question. Whenever you create anything in JS, it uses some existing prototype. It depends on what kind of item you are creating.
The below line is basically doing a lot of things in background. It is creating a function with name as 'A'. While doing so the JS engine uses an already existing special object in the browser called Function.prototype. This contains the basic characteristics of any function that you are creating. Then it creates a brand new object that has only two properties by default: constructor and a link to the default object prototype(referenced by proto). And then assign the new function definition that you have written to this newly created function.
function A(n){this.n=n;};
Hence we have two prototypes to understand here:
Function.prototype
A.prototype
Function.prototype would give that existing object we discussed above which is provided by the engine to create new functions.
A.prototype is the new object that gets created when A is declared. Note that we haven't yet used our new function A to create objects.
While running the below code, JS engine creates a new object which would inherit properties from A.prototype, runs the function definition which is stored in A(this.n = n etc..) and returns the newly created object.
let a = new A(1);
To summarize
a is an object that inherits from A.prototype
A is a function(a special object) that inherits from Function.prototype
I think now it should be clear what the below code means.
Object.getPrototypeOf(a) === A.prototype // true
Object.getPrototypeOf(A) === Function.prototype //true
Consider:
function Foo() {}
var x = new Foo();
now x and Foo have the same prototype, but only Foo responds to .prototype:
Object.getPrototype(x) === Foo.prototype // true
x.prototype === Foo.prototype // false
Foo.prototype // Foo {} (depending on which browser)
x.prototype // undefined
Why doesn't x.prototype work, but Foo.prototype does work?
prototype is a property of constructors that determines what the prototype of new objects created by that constructor will be. It's only useful to have such a property on a constructor.
As long as the prototype on the constructor hasn't been changed:
Object.getPrototypeOf( x ) === Foo.prototype
and that is the same as:
Object.getPrototypeOf( x ) === x.constructor.prototype
Note that generally:
Object.getPrototypeOf( Foo ) != Foo.prototype
Long story short: functions meant for new have prototype, object instances don't.
I'll probably fail in my precision in saying this, but the prototype is something that only applies to what you might call constructor functions, which are functions meant to be called with new to create instances. The prototype can be thought of as the template for the resulting instance.
For the resulting object, prototype is not a property. Rather, the properties in the constructor's prototype are available as properties on the instance that was created. Meaning that when you look up a property on the instance, if it's not defined on the instance, Javascript will begin checking the prototype chain to see if it's defined there.
If you want to access the prototype of an instance, use Object.getPrototypeOf.
The semantics of Javascript can be confusing. I highly recommend working through the free-to-read Javascript Allongé as a way to thoroughly understand some of Javascript's finer points. Chapter 8 focuses on exactly this topic.
I wanted to try manually walking the prototype chain of a few objects just to see what I find along the way. However, I got stuck on the first one that I tried. Here's the code:
function MyObject() { }
var x = new MyObject();
console.log('--------------------------------------------');
console.log('x.constructor.name: ' + x.constructor.name);
console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name);
console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.');
console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.');
console.log('--------------------------------------------');
The above code results in the following output in the Developer Tools Console of Google Chrome:
--------------------------------------------
x.constructor.name: MyObject
x.constructor.prototype.constructor.name: MyObject
No, you are wrong.
Good guess.
--------------------------------------------
It makes sense that x's constructor is the MyObject function, since x was instantiated using the new keyword on MyObject (this follows from the definition of a constructor). Because of this, I understand the first line of output (note: I started counting lines of output from zero on up). The second line, however, confuses me. I would like to know what MyObject's prototype is. Apparently, it isn't an object of type Function, as indicated by the 3rd line of output, which tells me that I'm wrong. The fourth line of output just reinforces the output from the first line.
On a more general note, I assumed that the correct way to walk the prototype chain of an object would be to go from the object in question to its constructor, and then from the constructor to the constructor's prototype, assuming that this last reference is not null. I assumed that this two-step process (consisting of going to the constructor, and then to the constructor's prototype) should be repeated until a null reference from a constructor to a prototype is reached, thus signifying the end of the prototype chain. This doesn't seem to be working, though, since application of this algorithm to the above scenario just leads to circular references.
In summary, I have two questions:
Why is x.constructor === x.constructor.prototype.constructor (or, in other words, why the circular references), and what kind of an object is x.constructor.prototype, anyway (or, in other words, how did it get instantiated / where did it come from)?
How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?
Edit
I came across a similar question on StackOverflow here, but it doesn't explicity ask the correct way to walk the prototype chain. It does point out the circular references, though...
In Javascript terminology, an object a's "prototype" refers to the object from which a inherits properties. The standards-based way to access this is with Object.getPrototypeOf:
var protoOfA = Object.getPrototypeOf(a);
There's also the old way, non-standard but supported by some browsers:
var protoOfA = a.__proto__;
But if you have a function F, F.prototype does NOT refer the object from which F inherits anything. Rather, it refers to the object from which instances created by F inherit:
function F() {};
a = new F();
console.log(Object.getPrototypeOf(a) === F.prototype); // true
When you define a function, an object is created to serve as the prototype of instances created by that function, and this new object is stored in the function's prototype property.
--
Functions behave like objects in many ways (e.g., they can have properties) but they aren't exactly like other objects:
console.log(typeof a); // "object"
console.log(typeof F); // "function"
Their "prototypes" are ill-defined (example run in Chrome) (this is apparently a Chrome-specific behavior)
console.log(Object.getPrototypeOf(F)); // "function Empty() {}"
console.log(Empty); // ReferenceError: Empty is not defined
--
The constructor property is strange. The interpreter doesn't care about it. MDN says, confusingly:
Returns a reference to the Object function that created the instance's prototype.
Further, you can change the value of constructor on an object, but this has no effect on what the object is or how it behaves - it's merely descriptive.
--
So, to answer your questions:
Why is x.constructor === x.constructor.prototype.constructor
No good reason. This is arbitrary behavior browsers have converged on.
what kind of an object is x.constructor.prototype, anyway
In this example, t's x's prototype, the same as Object.getPrototypeOf(x). But in general you can't rely on x.constructor or anything derived from it, because it's arbitrary.
How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?
for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
// do something with p
}
Yeah, this can be a bit difficult to grasp at first. I cannot do better than provide you some links. These always help me out when I am in trouble.
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
http://mckoss.com/jscript/object.htm
http://zeekat.nl/articles/constructors-considered-mildly-confusing.html
Q1: For the "why" see the references above. x.constructor.prototype is x.__proto__ that is the internal "real" prototype of x, at least in your case when no prototype and constructor properties were overwritten. It is created the moment you define the function MyObject.
Q2: Unfortunately you cannot do it this way. You can use the __proto__ property where it is supported, but see
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
I am trying to understand the new word in javascript. The top answer here What is the 'new' keyword in JavaScript? recommends this article.
In that article, in the prototypes section, the author says:
In other words, obj.prototype is in general not the obj's {Prototype}.
What does this mean? I have a hazy understanding of prototype (object that begets other objects). I understand that javascript does not have classes in the way that C# and Java have classes. Is that what the sentence above is expressing?
I'm not sure that article is the best way to understand what's going on here - it's a great technical explanation, but perhaps not the best way to get an intuitive understanding.
Let's step back and work this through.
A quick look at property lookup
One way to understand prototypal inheritance is to think of it as way to say "if I don't have it, look over there".
Say you've got an object and try to access a property that doesn't exist, JS will return the value undefined:
var x = {};
x.foo //=> undefined
All objects inherit from Object.prototype, so look what happens if we modify it:
var x = {};
x.foo //=> undefined
Object.prototype.foo = 'hello there';
x.foo //=> 'hello there';
What happened? When we initially create x, JavaScript sets up an internal [[Prototype]] property that points to Object.prototype. Effectively, there is a lookup algorithm that looks something like (pseudo-code):
Lookup(obj, prop) =
if HasProperty(object, property)
return GetPropertyValue(object, property)
else if HasPrototype(object)
return Lookup(PrototypeOf(object), property)
else
return undefined
In other words, start with the initial object, check for the property, if it doesn't have it, follow the prototype chain to keep looking for it. If we hit the end of the prototype chain, the property must be undefined.
So what about the new operator?
The new operator gives us a way to:
dynamically set the prototype of an object to something other than Object.prototype
do some initialization stuff when we create an object
NOTE: in ES5, we also have Object.create which gives you 1, but not 2.
When you say new Foo(a, b), here's what happens:
we make a new object that has its internal [[Prototype]] set to Foo.prototype.
we run the function Foo (its just a normal function) with its context (think this) set to the new object we just made
we return the new object after the function finishes (actually, if the function explicitly returns a value, we just return that value, but most of the time, we won't be doing that).
But wait, where did Foo.prototype come from?
Let's see - run the following in the console:
function Foo() {}
typeof Foo.prototype //=> "object"
When we create a function in JS, it comes with an object attached to its prototype property. It's just an object, like any other, so you can manipulate it, set/delete properties, even completely overwrite it (which the mentioned article shows an example of).
For example:
function Foo() {}
Foo.prototype.answer = 42;
var foo1 = new Foo();
var foo2 = new Foo();
foo1.answer //=> 42
foo2.answer //=> 42
// If you want you can change foo2's answer
foo2.answer = 'something else';
// Foo.prototype is unchanged
Foo.prototype.answer //=> 42
foo1.answer //=> 42 (still getting its answer from the prototype)
foo2.answer //= 'something else'
Getting back to the original question
Continuing with the foo example from above, what the original article was referring to is that foo1 and foo2 don't have prototype properties set on them:
foo1.prototype //=> undefined
foo2.prototype //=> undefined
NOTE: there is a non-standard __proto__ property that many JS engines provide that will give you an object's prototype, and in ES5, you also have Object.getPrototypeOf to get access to a given object's prototype.
Relevant links:
MDN's page on the new operator.
MDN's page on "working with objects".
I understand that javascript does not have classes in the way that C# and Java have classes. Is that what the sentence above is expressing?
No. While true, it has nothing to do with that sentence.
In other words, obj.prototype is in general not the obj's {Prototype}.
What does this mean?
An object might have a {prototype} (usually referred to as [[prototype]]), which is the object from which it does inherit properties. You can access that via the Object.getPrototypeOf() function, it is not a "visible" property of the object but some "hidden field".
Also, some objects (especially function objects) do have a .prototype property, i.e. a public attribute with the literal name "prototype".
The sentence states that these two "prototypes" are different from each other.
The question you linked now explains how the new keyword relates these different "prototypes". When you call a constructor function with new, then a new instance is created. The instance does inherit (its [[prototype]] will be set to) the prototype object of the "class" (which is shared amongst all instances) and that is looked up via the .prototype property of the constructor function.
As an example, let's look at the ObjMaker function from the code there. The ObjMaker.prototype (property) is the base for all ObjMaker instances. However, Object.getPrototypeOf(ObjMaker) is the object from which all function objects inherit from ([[prototype]]), which is Function.prototype.
The sentence means that you can't access an object's prototype using obj.prototype. You can access it with obj.__proto__ or Object.getPrototypeOf(obj) though. Also see the question __proto__ Vs. prototype in JavaScript.
The article is a bit dated. What it means is that prototype is a property. A property of a function object to be precise. It provides a way to define a prototype for objects created with this function. E.g.:
function Foo() {}
Foo.prototype.myMethod = function() {};
var myFoo = new Foo();
myFoo is an object and it has a prototype that contains the method myMethod.
The prototype of myFoo is not myFoo.prototype. That doesn't even exist.