That's not what the .prototype
property is for. Despite the name, the .prototype
property of functions isn't actually the prototype of the objects you're used to working with. This is one of the hardest things to understand about JavaScript, so it's not just you.
The key to understanding the prototype system in JavaScript is that the new
operator creates two objects, not one. I'm going to talk about this in terms of four variables:
- [[myPrototype]]
- The prototype of an object. Every object theoretically has one (though for some objects, it might be undefined).
- [[Constructor]]
- The function that is being called with the New operator
- [[newObject]]
- The object that will eventually be returned
- [[newPrototype]]
- The object that will become [[newObject]].[[myPrototype]]
Note that these aren't valid JavaScript names (in fact, they're not valid names in most programming languages). All of this happens behind the scenes, and most implementations don't use these names either. I'm doing this to make clear that you can't normally see these objects.
When you use the new
operator, JavaScript does roughly the following steps.
- Create an object [[newPrototype]].
- Set [[newPrototype]].[[myPrototype]] to [[Constructor]].prototype
- Create an object [[newObject]].
- Set [[newObject]].[[myPrototype]] to [[newPrototype]]
- Set [[newObject]].[[myPrototype]].constructor to [[Constructor]]
- Call [[Constructor]], with [[newObject]] as "this".
Note that [[newObject]].[[myPrototype]] isn't a perfect match for either [[newObject]] or [[Constructor]].prototype. That's why we need a third object between them: it carries the information you want to inherit (through [[newPrototype]].[[myPrototype]]), but it also carries information specific to the object you're creating (in [[newObject]].constructor).
And so we get to what the .prototype
function is for. It's not the function's [[myPrototype]], and it's not the [[myPrototype]] for the objects you create with new
. It's actually two levels back in the prototype chain, not one.
I hope this explanation helps you understand what the .prototype
function is for. This isn't simple stuff, and not every explanation clicks with everybody. That's part of why we have so many explanations here.
When you first create an object, you can set its prototype directly with Object.create()
. This function works with IE9 and higher (plus all other modern browsers), and it can be polyfilled if you need to work with older browsers. To see that prototype later, you use Object.getPrototypeOf()
, which also has decent browser support (though IE only supports it in version 9 and higher). Using only these two functions, you might create your objects like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = Object.create(x);
x.a = "ea";
x.b = "eb";
console.log(Object.getPrototypeOf(Object));
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);//this is undefined , why? i am expecting it to be "xc"
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
Once an object has been created, there isn't a standard way to reset its prototype yet. ECMAScript 6 defines one (the Object.setPrototypeOf() function), but so far only Chrome and Firefox support it: IE and Safari do not. Still, if that's OK, you could do things like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(Object.getPrototypeOf(object));
console.log(Object.getPrototypeOf(e));
Object.setPrototypeOf(e, x);
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
There is a non-standard way to reset an existing object's prototype, and it even enjoys good browser support nowadays. To do this, you set the .__proto__
property on any standard object. You could use it like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(object.__proto__);
console.log(e.__proto__);
e.__proto__ = x;
console.log(e.__proto__);
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(e.__proto__.a);
console.log(e.__proto__.b);
Now, onto your last question: why is Object.prototype
equal to {}, rather than undefined? Because the Object
constructor function has a .prototype
property, which becomes the default prototype of all Objects created through it. The specs call this object [[ObjectPrototype]], and it's where things like the .hasOwnProperty()
function live.