Javascript prototype behavior - javascript

I have a method that will let me select the prototype object when creating a new object (copied from "Javascript: The Good Parts" book):
Object.create = function(o) {
var F = function() {};
F.prototype=o;
return new F();
}
Now say, I have an object:
var car = {
model: "Nissan"
};
And I create a new object based on this object, using the "Create" method:
var car1 = Object.create(car);
I can then add a property to car and it will dynamically get added to car1 (dynamic prototyping). So for eg:
car.year=2011; // Gets added to "car"...
alert(car1.year); // ... Is also avaialable to car1
Q1) This behavior indicates that "year" got added to car's prototype, which is why it is available to car1. Is this correct? If not, then where does "year" get added and why is it available to both "car" and "car1"?
Also, per the rule of delegation, if a method cannot be found on an object, it will search its prototype and then check all the prototypes up the chain till it gets to Object.prototype. So now, if I type something like this:
Object.prototype.originCountry = "Japan";
alert(car.originCountry); // Outputs Japan
alert(car1.originCountry); // Outputs Japan
So far so good; however, if I do:
Object.carColor= "White";
alert(car.carColor); // Error!
Q2) When I add a property to "car" (see car.year example above, it gets added to car's prototype. However, when I add a property to Object, it does not get added to Object's prototype? If it does get added to Object's prototype, then why is it not available to "car", per the rule of delegation?
Why is this happening?

When you do this:
Object.carColor = "White";
Then the property carColor does not get added to the Object's prototype. It is now a property of Object. To see what you expect, what you would do is:
Object.prototype.carColor = "White";
Then after that:
alert(({}).carColor); // Will alert "White"
So what happens here is that. any object created including {} (which is nothing but an empty object) is a new instance of Object and hence shares the properties of whatever is set in the prototype of Object.
As for how your Object.create function works. Let us look at it line-by-line:
1. var F = function() {};
You just create a new function, an essentially blank object. The reason you use a function and not something like {} is because a function can be coupled with a new call to create a new instance of that object wherein the function would act as a constructor.
2. F.prototype=o;
You set the prototype of the new blank function to the object you've created. Now, this is purely a reference. It is not a deep-copy. What I mean is that as the object o changes, so will any instances of the objects (actually they won't change, but they would 'seem to' change. More on that later).
3. return new F();
Now you just create a new instance of that function, which has a prototype as the object you passed.
When you do the following:
var car1 = Object.create(car);
You get an object car1 which has the prototype has car. So when you do this:
car.year = 2011
It isn't like car1 changes. It is more like the object that the prototype refers to changes. So when you do something like:
car1.year
A search is made (first in the prototype, then in the object) for a property called year and turns out, that the prototype has it and hence car1.year will return 2011.
So the bottom line is this:
A prototype is shared amongst instances.
Changing the properties of an Object will not manifest into any instances changing.

In your first example, you are adding to the prototype of your car1 because car === F.prototype and car1 instanceof F. So to Q1: yes.
Object is the constructor function of all objects, as F is to your car1. If you add something on Object.prototype, it will be available on all objects - that's the reason why you should not, such non-enumerable properties mess up all for-in-loops. If you set a property of the Object constructor function, nothing changes for the things that inherit from it. Don't forget: Object equals the F function, not the o parameter for prototype setting. new Object() is like Object.create(Object.prototype).

That function doesn't let you select the prototype object it creates a nmew object constructor, the object argument as prototype and then return a new object based on the constructor.
That new object will inherit methods and properties from the object arguments. This is to allow the creation of new objects that inherits from others.
The reason this works (and by the way Object is a core javascript object and should not be extended)
Object.prototype.originCountry = "Japan";
alert(car.originCountry); // Outputs Japan
alert(car1.originCountry);
and this doesn't
Object.carColor= "White";
is because the first extend the prototype object of Object, which means object build with the Object constructor will inherits those methods and properties.
When the later is what we call a static function which does not get passed to object created from the Object constructor.
I would recommend reading more about prototypal inheritance in Javascript. here is few links.
http://www.webreference.com/programming/javascript/prototypal_inheritance/index.html
http://www.htmlgoodies.com/html5/tutorials/javascript-prototypical-inheritance-explained.html#fbid=xEJ2PwtH2Oh
http://unscriptable.com/2007/04/17/inheritance-explained/

Related

Why is prototype of my object undefined?

I created a Car object like this.
var Car = Object()
Then I added some properties to it like
Car.price = 5000;
Car.color = "red";
Then I created an instance of it like
var car1 = Object.create(Car);
What I don't understand is, when I call car1.prototype or Car.prototype, I get undefined.
According to what I've read, every Object is a prototype of something.
Can someone explain why it's "undefined"?
every Object is a prototype of something
No. Every object has a prototype (except the root object). However, only functions have a prototype property.
The value of that property will become the prototype of the objects that are created by calling the function as constructor function (e.g. var obj1 = new Constr();).
What I don't understand is, when I call car1.prototype or Car.prototype, I get undefined.
As just explained, only functions have a prototype property. car1 and Car are objects and therefore don't have such a property.
To get the prototype of an arbitrary object, you can use Object.getPrototypeOf:
var car1Prototype = Object.getPrototypeOf(car1);
Then I created an instance of it like var car1 = Object.create(Car);
You didn't create an instance of Car. If you created a new object and explicitly set its prototype to Car. Alternatively you could have defined Car as constructor function:
function Car(price, color) {
this.price = price;
this.color = color;
}
var car1 = new Car(5000, 'red');
Now that Car is a function, Car.prototype would yield the prototype of car1, i.e.
Car.prototype === Object.getPrototypeOf(car1);
See also Introduction to Object-Oriented JavaScript
Functions have prototypes. Object instances, like car1, don't.
It's correct to say that every object is a copy of some prototype. By default, objects are a copy of the prototype of the Object "function". However, object instances don't have a prototype themselves.
Think of a prototype as a "model" for a new Object. In Object Oriented languages, a class or a struct act like a strict model for new instances. That is, every instance of the Car class necessarily have motor, for instance. Likewise, in JavaScript, function prototypes act like the "model" for new instances of that function, but they are not strict. Once you create an instance from that model, you can add and remove members, because the language is dynamic.
EDIT
As Pointy clarified, it seems that object instances are not a copy of the "model" function prototype property. It seems that the prototype is copied to an internal object that is looked up when you try to access a property of the instantiated object.
Example:
var car1 = new Car();
// car1 now is not a copy of Car.prototype, but it has an internal object that is.
car1.motor = new V8Motor();
// even though motor is not a property of car1, this will work because JavaScript will find this property in the car1 prototype as it's not a member of the instance itself

Javascript `new` operator & prototype

Say we create a Function named 'Shape', and add a property 'name' & method 'toString' on it's prototype:
var Shape = function () {};
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
return this.name;
}
console.log(Shape.name); // ''
console.log(Shape.toString()); // function () {}
var Triangle = new Shape();
console.log(Triangle.name); // 'Shape'
console.log(Triangle.toString()); // 'Shape'
'NEW' operator did two things:
1. It points this to 'Triangle'
2. It points 'Triangle's [[proto]] to Shape.prototype
Then I can understand when I call name & toString on Triangle, it searches for it's prototype chain till Shape.prototype.
But my problem is why not Shape searching for it's property(even it's an Object) for the method & property?
Thanks.
When you access a property on an object, Javascript looks first directly on the object for any properties that have been added directly to the object (these are called "own" properties). If it doesn't find the property there, then it looks up the prototype chain.
So, when you do this:
var Triangle = new Shape();
console.log(Triangle.toString()); // 'Shape'
it looks for the .toString() property on the actual object named Triangle, but there is no property by that name directly on that object. So, since it didn't find anything on the object directly, it then looks on the prototype and it finds the Shape.prototype.toString() implementation there and that is what is executed.
A reference to the prototype is stored on the Triangle object when it is created. It is not stored in the .prototype property - that property is only used on the constructor. Instead, each JS version has its own way of storing a reference to the prototype and it has traditionally not been the same for all browsers and how it was stored was non-standard. It was originally meant only for internal use by the JS engine. For example, Chrome stores it on a property named obj.__proto__, but IE does not. To fix this lack of standardization, there is new method called obj.getPrototypeOf() which can now be used in modern browsers to get access to the prototype for a given object. In any case, the JS engine searches this prototype for you automatically when resolving property names that are not found on the actual object itself.
If you did this:
var Triangle = new Shape();
Triangle.toString = function() {
return 'Shape named Triangle';
}
console.log(Triangle.toString()); // 'Shape named Triangle'
Then, javascript would first find the toString() implementation that you attached directly to the object and it would execute that one rather than the one on the prototype.
So I am adding according to what I know.
Here Shape is a function & A function is just a special kind of object, and like any object a function can have properties.
Functions automatically get a property called prototype, which is just an empty object. This object gets some special treatment.
When you will do a new of a Function the created object inherits all of the properties of its constructor’s prototype.
Like bellow
var Shape = function () {};
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
return this.name;
}
When you will say
var Triangle = new Shape();
So what it does
var Triangle = {};
Triangle.name = Shape.prototype.name
Triangle.toString = Shape.prototype.toString;
"it sets up the object Triangle to delegate to Shape.prototype."
So when you will do
Triangle.name //Shape
Triangle.toString() // Shape
But for Shape you will have to say
Shape.prototype.name //Shape
Shape.prototype.toString() //Shape
because Triangle is an object, where Shape is a function (a kind of an object), therefore when you request for a property of a function and it will not find it, will not search throught it's prototype propery. But you can modify Function.prototype.name/toSTring()

Need help for javascript oops

var a = function () {};
a.prototype.test = function () {
alert("hello");
}
works fine but in following code
var b = new Object();
b.prototype.test = function () {
alert("hello");
}
i am getting this error TypeError: Cannot set property 'test' of undefined and i am unable to get it.
As per my understanding b has inherited prototype object from Object. So we should be able to add a new property in following manner say b.prototype.x = 1 .
But Object.prototype.x = 1 works .
typeof Object and a gives function but that of b is object
I am not getting why b.prototype.x = 1 doesnt work
Thanks.
Object is a function, which has a prototype property.
new Object() creates an object, which does not have a prototype property.
If you want to set the prototype of an object, you might mean setting the prototype of the object's constructor.
b.constructor.prototype.test = ...
To clarify some of the prototype/constructor nonsense:
A function has a prototype, which is an object. It specifies properties to add to an instance of that function.
An object has a constructor, which is a function. It specifies the function that was used to create the object.
Note that a function is an object, so it also has a constructor, which is Function.
This is a tricky issue -- there are two types of prototype fields, an internal one and an external one. The external one you can directly access with the normal prototype field as you are doing. The internal one is used to do lookups when a field/key is not found in the object.
If you do new blah(), it creates a new object whose internal prototype field is set to the external prototype field of blah. By default, the external prototype field of the newly constructed object is undefined. In particular, this is why evaluating b.prototype.x fails -- you can't do a field access on an undefined value. If you wish you can create a new object for a new external prototype, e.g. b = new Object(); b.prototype = {}.
You can see the internal/external prototype fields in action here:
Object.prototype.x = 4
b = new Object()
b.x // returns 4
What's happened is that b's internal prototype field points to Object.prototype, so lookups to b that fail are redirected to do a lookup in Object.prototype.
I'm not sure why, but newly created functions get their external prototype field set to Object -- this causes the first one to work.
You can refer to this resource
It doesn't work for the new object because it doesn't have a prototype property set. prototype property points to the Object that you have inherited. And since new Object() has had no object to inherit from, its prototype is set to undefined
A function on the other hand, has a super object (it inherited) by default.
You should be able to do it like this:
var b = {};
b.test = function() {
alert('Hello');
};

At what point is the prototype Object born in JavaScript?

Let's say I have a constructor function:
function Cat()
{
this.tail = "long";
this.colour = "black";
}
console.log(Cat.prototype);
// returns an empty [object Object] with no properties (checked with `for...in` loop).
So it seems at this point Cat.prototype doesn't havetail and colour.
var Charlie = new Cat();
console.log(Charlie.tail);
So how does Charlie inherit the properties of Cat if they are not defined in its prototype. I was under the assumption that the whole point of the prototype object is to mirror or store the properties of the constructor that will be inherited by all instances of cat- is this wrong?
At what point does the prototype Object get filled up with these properties? Or does this happen only when I explicitly set Cat.prototype.eyes = brown as an example?
Moreover, what is the correct approach for querying the properties of an Object's prototype? Is it a for...in loop? I guess it can't be Object.getOwnPropertyNames(Cat.prototype) because that would not return inherited properties.
You are defining the tail and colour properties directly on the instance. Those properties are not defined on the prototype object.
Btw, every function has a prototype property and it is created at the time when the function itself is created.
prototype is completely seperate from this.
All the things in this will not get inherited, the things in prototype will.
By default you inherit from Object.prototype (which is empty)
function Cat()
{
this.tail = "long";
this.colour = "black";
}
Cat.prototype.getColour = function () {
return this.colour;
}
WhiteCat.prototype = Cat.prototype;
WhiteCat.prototype.constructor = WhiteCat;
function WhiteCat(name){
Cat.call(this);
this.colour = "white";
}
var c = new Cat();
console.log(c.getColour()); // "black"
var w = new WhiteCat();
console.log(w.getColour()); // "white"
Prototypes in Javascript are a little different than what you are describing. In this case Charlie does have a tail because Charie IS A Cat that is, he is an instance of Cat the Cat class. In your Cat function you add the tail property to all cats with the this.tail = line. This happens entirely because you called the function Cat with the new keyword. When you do that, javascript creates a new object and then makes this point to that object in the context of the function.
Now prototypes work differently, they are best thought of as a chain that will be followed if a you go looking for a property or function that is not present in an object. For example, if try to go:
Charlie.tickle_wiskers();
Javascript will go looking for a function called tickle_wiskers in the charlie object. If it does not find that function it will look in Charlies prototype (which by default is Object.prototype if you don't set it explicitly). Finally I could give all Cats that function by going like this:
Cat.prototype.tickle_wiskers = function() {
alert('meow');
}
The prototype will never get the properties that you put in the object. The object has the members of the prototype, but the prototype doesn't have the members of the object.
The object doesn't inherit anything from the prototype, the members in the prototype still only exists in the prototype, they are only accessible from the object. If you remove something from the protype after an object is created, that member is no longer accessible from the object either.
A function has a prototype property, and when you use the new keyword to call the function as a constructor, the object that is created gets the prototype from the function.
If you add something to the prototype of a function, it will also be accessible by objects that were created using the function, even if you created them before adding it to the prototype:
function Cat() {}
var c = new Cat();
Cat.prototype.test = function() {
alert('test');
};
c.test(); // alerts 'test'
Moreover, what is the correct approach for querying the properties of an Object's prototype?
var myProto = Object.getPrototypeOf(someObject);
var names = Object.getOwnPropertyNames(myProto);
names.forEach(function (name) {
value = myProto[name];
...
});
Or does this happen only when I explicitly set Cat.prototype.eyes = brown as an example?
Yes, properties on the [[Prototype]] of an object are only set when you set them manually.
But since every "instance" of a prototype has a live pointer to the prototype object, these changes will reflect after the object has been created.
store the properties of the constructor that will be inherited by all instances of cat- is this wrong?
We don't store properties of objects on the prototype. We store properties (mainly methods) that we want to share among all instances of a prototype/constructor.

Isolating the Inheritance into a Function

http://jsbin.com/ifoguf/14/edit#javascript
I attempted Isolating the Inheritance Part into a Function, but when I create the object nothings is alerted, no errors are returned, so I'm stumped how to debug, and for a solution.
function Shape(){}
// augment prototype
Shape.prototype.name = 'shape';
Shape.prototype.toString = function() {return this.name;};
function TwoDShape(){}
// augment prototype
TwoDShape.prototype.name = '2D shape';
function Triangle(side, height) {
this.side = side;
this.height = height;
}
// augment prototype
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function(){return this.side * this.height / 2;};
var myTriangle = new Triangle(5, 10);
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(TwoDShape, Shape);
extend(Triangle, TwoDShape);
var myTriangle = new Triangle(5, 10);
alert(myTriangle.getArea());
alert(myTriangle.toString());
var s = new Shape();
alert(s.name);
TIA
Your code seemed a bit complex. See a simpler example (remember to switch on a debugging tool to see log messages).
It's worth noting that inheritance in JavaScript works by following prototype chains. That means every object holds a reference to a prototype object. This prototype object is just any ordinary object, too. The key is is that whenever a property (or function) is not found within an object, its prototype object is checked. This follows the prototype links until either a value was found or no prototypes are left over.
The prototype link is stored within an object whenever an object is created and points to the object as specified in the prototype property of the object's constructor function. You can inspect the prototype in Firefox by checking an object's __proto__ property.
In the linked example, there are 3 constructors:
Shape
Triangle
createPrototype (helper to get an empty object with defined prototype link)
In the linked example, there are 2 prototype objects:
Shape.prototype (contains shared properties for shapes)
Triangle.prototype (contains shared properties for triangles)
First a shape is created by calling new Shape(). This creates a new object since new is written in front of the function named Shape. The prototype link of the object (__proto__ in Firefox) points to Shape.prototype because this property of the constructor function gives the prototype link's target. The link is set on object instantiation.
As a result whenever you try to access a property of the shape the property is retrieved as follows. First, shape is searched for the property. If it's there, use it. If not, the prototype object shape.__proto__ is retrieved which refers to the same object as Shape.prototype. Now, the prototype object is searched for the property.
For the case of triangle the thing is a bit more complex because multiple prototype links are involved. The important thing is that we need to create an empty object to hold the triangles' shared properties which also needs to have its prototype link set to point to Shape.prototype. This makes shape's prototype the fallback of triangle's prototype.
It is archived by the anonymous function that includes createPrototype. It needs to be included because every invocation of the anonymous function needs to manipulate the prototype property of a constructor function (called createPrototype in our case). After the empty prototype object with the prototype chain is created, it is instantly returned and assigned to Triangle.prototype. After that any object created by new Triangle() has the desired prototype chain.
Once this is set, we can add all shared properties of triangles into the Triangle.prototype object that was just created. This is shown by overriding paint and by adding getArea. Note this overriding actually works because the paint function for triangles is found earlier than the paint method for shapes and the first found reference/property is used.
To summarize, all property accesses on objects use prototype chains for fallbacks. In our case the chain for shape is shape→Shape.prototype and the one for triangle is triangle→Triangle.prototype→Shape.prototype.
You might want to assign a name to the anonymous function (that includes createPrototype) to have a tool for created object hierarchies. This is shown in the updated example and ends up with the following helper:
function makePrototype(parent){
// We need a new object whose prototype link points to parent.prototype
function createPrototype(){
}
createPrototype.prototype = parent.prototype;
return new createPrototype();
}

Categories

Resources