I'm learning prototypal inheritance in Javascript, and for my understanding I'm trying to use it to send the process into infinite recursive chaining.
My idea of prototypal inheritance is that an object (which is a function) holds prototype link. Any instance of that object points to it. So if I say instance.someproperty it looks into the prototype chain of the parent object.
Assuming this, If I just point function prototype list to itself, it should go into infinite loop when object tries to access some property.
var p = function(){};
p.prototype = p;
// I also tried p.prototype = new p();
var q = new p();
// and now when I say q.something, it should never be able to find it.
I want to know why this doesn't work and how can I make it to go into infinite loop.
Using more common style:
function P(){};
P.prototype = P;
In ECMA-262, the internal prototype property is denoted by [[Prototype]].
Assigning a different object to P.prototype does not modify P's [[Prototype]], so its inheritance chain remains as:
P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null
Given that P and P.prototype both point to the same object, the [[prototype]] chain of an instance of P is:
p : p[[Prototype]] -> P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null
so no endless loop.
Without the assignment to P.prototype, p's prototype chain would have been:
p : p[[Prototype]] -> P.prototype -> Object.prototype -> null
To get an endless loop, you can assign an object to its own __proto__ property (the public way to access [[Prototype]]) in those browsers that support it, but I'm not sure that's a good idea, Firefox throws:
"TypeError: cyclic __proto__ value".
Well, to your first question:
var p = function(){};
p.prototype = p;
// I also tried p.prototype = new p();
var q = new p();
In the first one, all you're doing when you create an instance of p is setting the prototype to the function p itself, which is an object in its own right (with properties such as length, prototype, etc.). Its actual internal prototype is Function.prototype, which in turn has a prototype of Object.prototype.
The second one is slightly different -- close, but no cigar. When you're assigning new p() to p.prototype, the prototype property has not been set yet, so you're just going to get the original value of the prototype property as the instance's internal prototype.
Moving on to your second question. I don't actually see why you'd do this, as every property would be shadowed by its own instance property.
Even if you were allowed to (no browsers do), there would be no point.
Consider this:
var a = { b: 1 };
a.__proto__ = a;
Let's assume that this works, ignore the fact that this throws a TypeError in all browsers (which is specified for browsers in Annex B of the upcoming ES6 spec).
If you were to access the property b, you'd never go up the prototype chain.
If you attempted to access a non-existent property, an implementation (if it allowed for such a thing) could either go up the prototype chain, back to itself recursively, or recognise that the property would never be found and return undefined.
Of course, there is the situation where there are multiple objects involved:
var a = { x: 1 };
var b = { y: 2 };
b.__proto__ = a;
a.__proto__ = b;
However, this is ridiculously stupid and of no practical use (if permitted in the first place -- it isn't).
Related
I have been reading through Mozilla Developer Network lately on JavaScript inheritance model. I am highly confused on one point. Here's the code from MDN:
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function(v) {
this.vertices.push(v);
}
};
var g = new Graph();
console.log(g.hasOwnProperty('vertices'));// true
console.log(g.hasOwnProperty('addVertex'));// false
console.log(g.__proto__.hasOwnProperty('addVertex'));// true
What I don't understand is that why does g.hasOwnProperty('addVertex') yields false since addVertex is a property of g although it's defined in Graph's prototype but still it is part of Graph.
Also I had one more question: that if some object inherits from g (or so to say Graph) will it inherit only addVertex (those defined in Prototype of function) or it will inherit all three properties of graph namely vertices, edges and addVertex.
why does g.hasOwnProperty('addVertex') yields false
That is the way hasOwnProperty works. From MDN:
The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as own (not inherited) property.
So hasOwnPropertydoes not traverse the prototype chain when do its checks.
You can use in operator to check property in prototype chain.
Because hasOwnProperty specifically says it return false on inherited properties
MDN:
The hasOwnProperty() method returns a boolean indicating whether the
object has the specified property as own (not inherited) property.
As for your second question - it depends on exactly how you have an object inherit from Graph. In the ES5 way, I would do this:
var InheritedFromGraph = function() {
Graph.call(this);
}
InheritedFromGraph.prototype = Graph.prototype;
and then, yes, InheritedGraph will get the properties verticies and edge that Graph defined in it's constructor.
I'm trying my best to understand javascript. Here is a simple experiment in Chrome console which gets me very confused:
var foo=function(){this.p=1;}
foo.prototype.p=2;
var bar=new foo();
//foo{p:1,p:2} <- this is the output of Chrome console, from the last command above
The output of Chrome is what confuses me. It seems like bar is an object with 2 parameters, p:1 and p:2. Does this mean bar has 2 p??? What is the reasoning behind this?
Chrome DevTools console's inline (non-extended) object representation currently does not display any difference between own properties and inherited prototype properties.
Now let's break what's going on into smaller steps.
new foo() creates a new object whose internal proto property points to foo.prototype. This means this object can access all properties defined in foo.prototype. It's called prototype chain.
Now when you set a property of the same name in the object, it "shadows" the prototype's property by the same name, turning the latter inaccessible through regular property access (see #loxxy's answer using Object.getPrototypeOf(obj) to access the shadowed prototype property).
Once you add a function to the object or its prototype, the console allows you to display the extended object representation, which does differ own properties from prototype properties. In the next example I've added a q method to the prototype to allow this behavior. The properties inherited from the prototype are shown inside the object's proto internal property:
If you just want to have the number of instanced objects in the constructor's prototype, you can use:
var foo = function() {
Object.getPrototypeOf(this).p++;
}
foo.prototype.p = 0;
console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}
Or without the ES5 dependency:
var foo = function() {
foo.prototype.p++;
}
foo.prototype.p = 0;
console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}
Yes. Sort of.
bar has both:
A p property of its own.
bar.hasOwnProperty('p'); // true
bar.p; // 1
A p property still remaining on the prototype that it has through inheritance.
Object.getPrototypeOf(bar).p; // 2
Though, only 1 of them is accessible directly from bar at a time, with preference to the own property.
bar.p; // 1
delete bar.p;
bar.p; // 2
And, Chrome is showing both because it's traversing the prototype chain and looking for any enumerable properties.
The bar object has only one p with value 1
The earlier p with value 2 can be viewed in a readonly object which you can access with getPrototypeOf:
Object.getPrototypeOf(bar).p
You see both because the developer toolbar is designed to print an XML representation of the specified object which should intuitively show all the properties, whether directly accessible or not.
var foo=function(){this.p=1;} is constructor and executes after var bar=new foo();. So at the beginning p=2 and then p becomes 1. So:
var foo=function(){
// here this.p is equal to 2
this.p=1;
// here this.p is equal to 1
}
foo.prototype.p=2;
var bar=new foo();
EDIT:
JSON.stringify(bar);
When you acces a property, the javascript engine will seek it on the object instance, then on all its prototype chain.
So the meaning of p as a prototype property is to have a default value for p, wether you define it on any instance of the class or not. One example might be the number of wheel for a vehicle, that could default to 4, for instance.
If later you write to this property :
function Vehicle() {};
Vehicle.protoype.wheelCount = 4;
var myBike = new Vehicle();
myBike.wheelCount = 2 ; // this is a bike.
You won't change the value set on the prototype, but rather you'll create a new property on the instance, having the new value, so for instance :
var myCar = new Vehicle();
myCar.wheelCount // === 4
Now the very scenario you mention -setting a default value, and setting also an instance value in the constructor - doesn't make much sense, since you will have to use Object.getPrototypeOf to get to reach the default value. This is just a possibility that is of no use, just like there are many in all languages.
Some projects use Object.create() or Object.defineProperties() function. I wonder is is recommended? Whats the difference between
x = Object.create(null);
vs
x = {}
And
x = {}
x.__proto__.hello = function() {
console.log("hello");
}
vs
x = Object.create(null);
Object.defineProperty(x, "hello", {
value: function() {
console.log("hello");
}
});
defineProperty/create seems very verbose and long to me. When/Why do I use them? Perhaps the good might be to enforce getters/setters/overriding properties?
There is a huge difference. Have a look at the docs!
Object.create does create an Object that inherits from the first argument, null in your case. In contrast, {} - or new Object() - creates a new object that inherits from Object.prototype.
__proto__ is non-standard and should not be used. However, in your case you just do Object.prototype.hello = function() {…};. Never extend that object with enumerable properties, never ever!
Object.defineProperty does define a property on an object with a special descriptor object. The enumerable, configurable and writable attributes default to false, which means that you wont be able to delete x.hello for example, or assign any other value.
Your first snippet creates a plain object, which inherits a hello method from Object.prototype, while your second snippet creates an object inheriting from nothing and having a non-editable hello property. I don't see much relatedness.
This is a purely trivial question for academic value:
If I create a new object, either by doing:
var o = { x:5, y:6 };
or
var o = Object.create({ x:5, y:6 });
when I query the o.prototype property, I get undefined. I thought that any newly created object automatically inherits the Object.prototype prototype.
Furthermore, invoking toString(), (a method of Object.prototype) on this object works just fine, implying that o does inherit from Object.prototype. So why do I get undefined?
There is a difference between instances and their constructors.
When creating an object like {a: 1}, you're creating an instance of the Object constructor. Object.prototype is indeed available, and all functions inside that prototype are available:
var o = {a: 1};
o.hasOwnProperty === Object.prototype.hasOwnProperty; // true
But Object.create does something different. It creates an instance (an object), but inserts an additional prototype chain:
var o = {a: 1};
var p = Object.create(o);
The chain will be:
Object.prototype - o - p
This means that:
p.hasOwnProperty === Object.prototype.hasOwnProperty; // true
p.a === o.a; // true
To get the prototype "under" an instance, you can use Object.getPrototypeOf:
var o = {a: 1};
var p = Object.create(o);
Object.getPrototypeOf(p) === o; // true
Object.getPrototypeOf(o) === Object.prototype; // true
(Previously, you could access an instance's prototype with o.__proto__, but this has been deprecated.)
Note that you could also access the prototype as follows:
o.constructor === Object; // true
So:
o.constructor.prototype === Object.prototype // true
o.constructor.prototype === Object.getPrototypeOf(o); // true
This fails for Object.create-created objects because they do not have a constructor (or rather, their constructor is Object and not what you passed to Object.create because the constructor function is absent).
Not a direct answer, but knowledge that everybody, who deal with inheritance in Javascript, should have.
Prototype inheritance in Javascript is a tricky concept. Up until now, it has been impossible to create an empty object (by empty I mean lacking even properties form Object via prototype). So this means that creating a new object always had a link to the original Object prototype. However, according to the specification, the prototype chain of an object instance isn't visible, but some vendors have decided to implement their own proprietary object properties so that you could follow it, but it's highly recommended not to use it in production code.
The following sample code demonstrates just two ways of creating an object instance.
var someObject = {};
var otherObject = new Object();
var thirdObject = Object.create({});
Even though you don't manually add object properties to empty curly braces, you still get automatically added prototype chain. The same goes for the second example. To visualize it better, you can type those lines into Chrome console and then enter either someObject, otherObject or thirdObject to see details. Chrome shows the prototype chain by adding a proprietary property __proto__ which you can expand to see what is inherited and where it's from. If you executed something like
Object.prototype.sayHello = function() {
alert('hello');
};
you would be able to call it on all instances, by executing otherObject.sayHello().
However, using something that was implemented quite recently (therefore not supported by all browsers), you can actually create a truly empty object instance (doesn't inherit even from Object itself).
var emptyObject = Object.create(null);
When you enter it into Chrome console and then expand the emptyObject to see it's prototype chain, you can see that it doesn't exist. So even if you implemented the sayHello function to Object prototype, it would be impossible to call emptyObject.sayHello() since emptyObject does not inherit from Object prototype.
Hope it helps a bit with the general idea.
JavaScript has two types of objects: function object and non-function object. Conceptually, all objects have a prototype (NOT A PROTOTYPE PROPERTY). Internally, JavaScript names an object's prototype as [[Prototype]].
There are two approaches to get any object (including non-function object)'s [[prototype]]: the Object.getPrototypeOf() method and the __proto__ property. The __proto__ property is supported by many browsers and Node.js. It is to be standardized in ECMAScript 6.
Only a function (a callable) object has the prototype property. This prototype property is a regular property that has no direct relationship with the function's own [[prototype]]. When used as a constructor ( after the new operator), the function's prototype property will be assigned to the [[Prototype]] of a newly created object. In a non-function object, the prototype property is undefined . For example,
var objectOne = {x: 5}, objectTwo = Object.create({y: 6});
Both objectOne and objectTwo are non-function objects therefore they don't have a prototype property.
I'm creating javascript object by doing something like:
function field(name,label){
this.name = name
this.label= label;
}
var a = new field("market","Mkt").
Then I assign a to another object.
object.newField = a;
The second way of doing it is to create a new property directly
object.2ndNewField = {
name: "market2",
label:"Mkt2"
}
I try to read the objects in other functions. They behave differently, however, when i stringify the object, it looks ok. What's the difference between the two properties i created?
btw is there any difference of the following object?
object.2ndNewField = {
"name": "market2",
"label":"Mkt2
}
The difference is that in the first case, the created object inherits from field.prototype then Object.prototype (i.e. its internal [[Prototype]] is field.prototype, whose internal [[Prototype]] is Object.prototype), where as in the second case it inherits only from Object.prototype.
Another way to look at it is:
object.newField instanceof field; // true
object.newField instanceof Object; // true
object.newField2 instanceof field; // false
object.newField2 instanceof Object; // true
or the inheritance chains are:
object.newField -> field.prototype -> Object.prototype -> null
object.newField2 -> Object.prototype -> null
where '->' means "inherits from".
For the First option...Stay away from using "new". You can badly effect your global namespace if "new" is used wrong, or omitted when it should be used. Plus you have to be careful with the use of "this" in some places within your code, as it could be bound to something that you don't think it is, or even to your global data.
In your 2nd option you gave, you can safely use it for objects that are only used as a collection of data/methods (i.e. not "class-like" behavior) . If you want something that you can create multiple instances of with private and public variables/methods and can be inherited from, then you should use a function that returns an object.
I did a pretty big write up and example here of how to safely create base objects and use inheritance. If you follow the link, you will see why I didn't retype it all on this post ;).
Hope this helps...