Inheritance and the prototype chain - javascript

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.

Related

I don't understand writable and configurable property attributes of Objects

I don't understand the Writable and Configurable attributes of Objects. For example, in the MDN for Object.prototype, there is a table where I can clearly see that Configurable, Writable and Enumerable Property Attributes of Object.prototype are locked.
However, I can write and extend Object.prototype, for example with the following code:
// Example 1
Object.prototype.testing=999;
console.log(Object.testing); // 999
// Example 2
var o = {};
console.log(o.testing); // 999
What the MDN is referring to is the property prototype of Object itself. You cannot overwrite Object.prototype itself. If you try and make Object.prototype undefined, that will fail:
Object.prototype = 1;
console.log(Object.prototype); // [object Object]
If you try this in strict mode, you will get a TypeError upon attempting to assign to a non-writable property:
'use strict';
Object.prototype = 1; // TypeError: Cannot assign to read only property 'prototype' of function Object() { [native code] }
You can write to an object's own properties without changing what the object's reference is, and those have separate attributes. For example, see this:
var descriptor = Object.getOwnPropertyDescriptor(Object.prototype, 'toString');
console.log(descriptor.writable); // true
console.log(descriptor.enumerable); // false
console.log(descriptor.configurable); // true
There is a separate [[Extensible]] internal property that prevents the creation of new properties on an object -- this is set to false if you call Object.preventExtensions, Object.seal or Object.freeze.
Note that it's not a good idea to call Object.freeze on something like Object.prototype, as really weird things can happen:
Object.freeze(Object.prototype);
var building = {};
building.name = 'Alcove Apartments';
building.constructor = 'Meriton Apartments Pty Ltd';
console.log(building.constructor); // function Object() { [native code] }
Just like the previous example, it will also throw a TypeError in strict mode.
Basically, even though it would be a property on the object itself, it uses the attributes from the prototype chain to check whether or not it can assign the property. This has been considered as a mistake in the language by some people, however others consider this behaviour to be by design.
From: http://ejohn.org/blog/ecmascript-5-objects-and-properties/
Writable: If false, the value of the property can not be changed.
Configurable: If false, any attempts to delete the property or change its attributes (Writable, Configurable, or Enumerable) will fail.
Enumerable: If true, the property will be iterated over when a user does for (var prop in obj){} (or similar).
The Writable, Enumerable and Configurable attributes in MDN appear to be about the Object.prototype object itself, not its properties.
So, what that means is that you can't replace Object.prototype with a different object, but you are allowed to add properties to it.
So, what that means is if you do this:
Object.prototype = {foo: "whatever"}; // doesn't work - is just ignored
var j = {};
console.log(j.foo); // undefined
Then, the first line of code won't do anything.
I can clearly see that Configurable, Writable and Enumerable Property Attributes of Object.prototype are locked.
However, I can write Object.prototype.
No. The writability only concerns the prototype property of the Object object:
Object.prototype = {}; // Error: Invalid assignment (in strict mode)
// simply fails in lax mode
And I can extend Object.prototype
Yes. You can extend the Object.prototype object (regardless how you refer to it); that's a different attribute (of the object, not of a single property):
var proto = Object.getPrototypeOf({});
proto.testing1 = 9999; // works
Object.preventExtensions(proto);
proto.testing2 = 9999; // Error: Invalid assignment (in strict mode)

Infinite prototypal inheritance in Javascript

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).

Object.defineProperties/create really needed?

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.

Does a new object in Javascript have a prototype property?

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.

Why do we need the isPrototypeOf at all?

this page states:
Note: isPrototypeOf differs from
instanceof operator. In the expression
object instanceof AFunction, the
object prototype chain is checked
against AFunction.prototype, not
against AFunction itself
Ok I don't really get what they are trying to tell us. Isn't object instanceof AFunction exactly the same as `AFunction.prototype.isPrototypeOf(object)? or am I wrong?
Why do we need the isPrototypeOf at all?
If i ever need to do p.isPrototypeOf(o) couldn't I just do o instanceof p.constructor ?
Addtionally, is p.isPrototypeOf(o) functionally equivalent to p===Object.getPrototypeOf(o)?
Object constructors are funky things. From this answer:
As Pointy has pointed out, in his
answer
The "constructor" property is a
reference to the function that created
the object's prototype, not the object
itself.
The usual way to deal with this is to
augment the object's prototype
constructor property after assigning
to the prototype.
An object's constructor is not read-only, which is why this is possible to do at all. I could assign any value to p.constructor after p is created, and this would completely break using
o instanceof p.constructor
instead of
p.isPrototypeOf(o)
Further reading
constructor # MDC
What it the significance of the Javascript constructor property?
OO Programming in JS
Constructors considered mildly confusing
Edit re: OP edit
Addtionally, is p.isPrototypeOf(o) functionally equivalent to p===Object.getPrototypeOf(o)?
Those are more similar than your original question, aside from the fact that Object.getPrototypeOf wasn't introduced until JavaScript 1.8.1? See John Resig - Object.getPrototypeOf. Perhaps more relevant, the two functions are different in the spec! (warning, PDF link)
I think the most important distinction here is that the isPrototypeOf method allows you to check if an object inherits directly from another object. Consider the following:
var t = new Object();
var f = new Object();
var c = Object.create(t);
c instanceof f.constructor; // true
c instanceof t.constructor; // true
f.isPrototypeOf(c); // false
t.isPrototypeOf(c); // true
As you can see the constructor is only the function that instantiated the object. Not the implementation specifier. So if t.y = function(){ return true; } and f.y = function(){ return false; } and I needed to check that c would return the appropriate implementation through it's prototype chain, instanceof wouldn't help very much.
instanceOf --> This object (or the objects it was derived from ) used the named object as a prototype
isPrototypeOf --> This object was used by the named Object (or the Objects it was derived from) as a prototype.
ie.
instanceOf is querying the objects ancestors.
IsPrototypeOf is querying the objects descendants.

Categories

Resources