I AM trying to understand js prototype property: my sample code
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
Container.prototype.stamp = function (string) {
return this.member + string;
}
document.write(newc.stamp('def'));
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
var b = new Box();
document.write(newc.test);
here the last line is undefined - even though Container's prototype is a Box and Box's prototype has a property test, why is the newc which refers to test in Box doesnt work? can any one please explain how the 'Prototype' works in my above context.
Thanks...
You are setting Container prototype to Box() after the newc instance was already created.
Reorder the statements as follows:
function Container(param) {
this.member = param;
}
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
Container.prototype.stamp = function (string) {
return this.member + string;
}
//Here the containers prototype setup is complete.
var newc = new Container('abc');
document.write(newc.stamp('def'));
document.write(newc.test);
If sounds like you want to know WHY it is behaving the way it is, and not just "fix" the code. So here's what's going on.
As you saw, if you change the prototype of "Container", you will actually change the properties for new objects AND objects already instantiated. So:
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
// setting a new property of the prototype, after newc instantiated.
Container.prototype.stamp = function (string) {
return this.member + string;
}
// This already-instantiated object can access the stamp function
document.write(newc.stamp('123')); // output: abc123
So there's no problem with the above, as long as you don't call the new method before it's defined. Now the next point. Add this to the above:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
var newd = new Container('fgh');
document.write(newd.stamp('456')); // output: ERROR
Error! But that makes sense, right? You totally wiped out the "Container" prototype and replaced it with the one from "Box", which has no "stamp" function.
I am going to assume you want "Box" to inherit from "Container". That would be logical from the naming convention. If you want to do that, replace the previous section with this:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
// This inherits from Container. Note that we can
// do this before or after we declare "Box"
Box.prototype = new Container();
Box.prototype.test = "Whatever";
var b = new Box("jkl"); // note: "jkl" is ignored because "Box" sets "member" to "why"
document.write(b.test); // output: Whatever
document.write("<br>");
document.write(b.stamp("345")); // output: why345
So now we have a "Box" that can call its own methods and parameters, and also call them from its parent "Container".
So the big picture is that an object will look at its own prototype for a method or something, and if it doesn't find it there it will look in the prototype of the thing it inherited from, and so on. The other big point is that setting something in the prototype makes it immediately available in all future AND current instances of that object.
An object does not contain a reference to its constructor which it uses to get at the prototype. If it did, then the code would work as you expected.
Instead, an object contains a reference to its prototype that is set when it is created.
From the language spec section 4.2.1:
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.
Related
I am new in JS, lets have a look on my code bellow.
I want to change value of legs property of mouse to 2 while using proto but I am unable to change it. All I am getting in output is 4. Please help why is this ?
function Animal() {
this.legs = 4;
}
var mouse = new Animal();
mouse.__proto__.legs = 2;
console.log(mouse.legs);
You can't change instance property this way.
mouse.__proto__ contains constructor function Animal.
If you want to change only mouse's legs you have to do it this way:
mouse.legs = 2
If you want to change every future animals - you unfortunately can't. new Animal() will always reference to original constructor function.
When you call new Animal, the JS engine doesn't reference Animal.prototype.constructor, it uses the Animal as the constructor function and Animal.prototype as the newly created object's prototype, ignoring Animal.prototype.constructor.
As commented, the leg you are trying to access is a self owned property and not on prototype.
Following is a sample:
function Animal() {
this.legs = 4;
}
Animal.prototype.legs = 8;
var mouse = new Animal();
mouse.legs = 2;
console.log(mouse.legs, mouse.__proto__.legs);
That said, if you wish to have a override concept implementation, always remember, never mutate/change property on prototype.
Idea is to have common property on prototype and have custom property on self.
Following is a sample depicting the same:
function Animal() { this.legs = 4; }
function Reptile() { this.legs = 4; }
Reptile.prototype = new Animal();
var mouse = new Reptile();
console.log('Mouse details : ', mouse.legs, mouse.__proto__.legs);
var snake = new Reptile();
snake.leg = 0;
console.log('Snake details : ', snake.legs, snake.__proto__.legs);
snake.__proto__.legs = 0;
console.log('After mutation')
console.log('Mouse details : ', mouse.legs, mouse.__proto__.legs);
console.log('Snake details : ', snake.legs, snake.__proto__.legs);
To simply put, everything in JS is an object. When you create an object, it has 2 nested levels by default:
-> this
-> __proto__
Any property of your constructor goes to this. Any property on its prototype goes to __proto__. Since all objects are inherited from Object, there is a chain till global object.
All JavaScript objects inherit properties and methods from a prototype. Once it gets inherited, you can directly call or change the value of it.
function Animal() {
this.legs = 4;
}
var mouse = new Animal();
// mouse.__proto__.legs = 2;
//instead do this
mouse.legs = 2;
console.log(mouse.legs);
I'm not sure if the Title actually made any sense but however I'm trying to set a functions prototype to "sub classes" prototype.
For coming example;
What I try to do is : I have a user and paidUser . paidUser is subclass ofuser
User Factory function :
function userCreator(name, score) {
this.name = name;
this.score = score;
}
userCreator.prototype.sayName = function(){console.log("hi");}
userCreator.prototype.increment = function(){this.score++;}
And I can create a new user with new keyword. so far so good.
const user1 = new userCreator("Phil", 5);
Now , coming to Subclassing . (accountBalance is just a silly property special for paidUser for my example)
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
this.accountBalance = accountBalance;
}
now I want to set prototype of my userCreator as the prototype of paidUserCreator Factory Function
The following line works perfectly, but I don't understand it quite. Object.create function is supposed to created an empty object and that empty objects __proto__ must be the given parameter.
paidUserCreator.prototype =Object.create(userCreator.prototype);
paidUserCreator.prototype.increaseBalance = function(){
this.accountBalance++;
}
Another point what I don't understand is :
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
For completion :
const paidUser1 = new paidUserCreator("Katarina", 4, 12);
PS: Yes I know the Class keyword is much cleaner and nicer to read but I want to learn how to do it in this way.
Starting with the last question:
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
It will, but you need to set the prototype of paidUserCreator.prototype not the function paidUserCreator so that when an instance looks for something on the paidUserCreator.prototype and doesn't find it, it will look to userCreator.prototype.
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function() {
console.log("hi");
}
function paidUserCreator(paidName, paidScore, accountBalance) {
userCreator.call(this, paidName, paidScore);
}
Object.setPrototypeOf(paidUserCreator.prototype, userCreator.prototype);
let p = new paidUserCreator("Mark", 98, 200.5)
p.sayName()
paidUserCreator.prototype = Object.create(userCreator.prototype) is similar. Object.create makes a new object and sets it's prototype to point to the object passed in. When you do this you are replacing paidUserCreator.prototype with a new object that is prototype linked to userCreator.prototype. One caveat with this is that if there is anything on paidUserCreator.prototype that you need it will be lost because you are replacing the whole object, not just setting the prototype.
Here's an example where that might bite you:
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function(){console.log("hi");}
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
}
// points to the paidUserCreator function
console.log(paidUserCreator.prototype.constructor)
// replace protoype with new object
paidUserCreator.prototype = Object.create(userCreator.prototype);
// now paidUserCreator.prototype has no constructor property
// so it defers to paidUserCreator
console.log(paidUserCreator.prototype.constructor)
please clarify the difference b/w this two codes
function Person(gender) {
this.gender = gender;
alert('Person instantiated');
}
Person.prototype.sayHello = function()
{
alert ('hello');
};
var person1 = new Person('Male');
var person2 = new Person('Female');
// call the Person sayHello method.
person1.sayHello()
and the second one is below where function define inside funciton (without prototype property)
function Animal(gender) {
this.gender = gender;
alert('animal instantiated');
this.sayToodle = function()
{
alert ('GOOOOOOO!!');
};
}
var Animal1 = new Animal('Male');
var Animal2 = new Animal('Female');
Animal1.sayToodle();
my more simple question are:
what is the difference?
define method inside or out side of a function. what is the effect?
if both same then which is the fine way to define this.
and what does prototype do?
Can we not define method of a obj out side of its function(CLASS)???
Defining a member inside the constructor (such as: this.name) gives only that instance of the object access to that member.
Defining a member inside the prototype allows all instances to "share" that property.
A way that helped me understand this was to define an array (or any other member that is not a method) inside the prototype, like so:
function Animal() {}
Animal.prototype = {
kids: [],
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten','another kitten','yet another kitten');
// cat.kids === ['kitten','another kitten','yet another kitten'];
// giraffe.kids === ['kitten','another kitten','yet another kitten'];
If you notice, the giraffe's kids were set (as kittens). Why is this? Because in this case, .giveBirth() accesses the prototype's kids array, which is shared by all instances.
What if we don't want to share the members, because the members are unique? You can do like so:
function Animal() {
this.kids = [];
}
Animal.prototype = {
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten');
// cat.kids === ['kitten']
// giraffe.kids == undefined
giraffe.giveBirth('baby giraffe');
// cat.kids === ['kitten']
// giraffe.kids === ['baby giraffe']
As you pointed out in the comments, part of how you decide to define the properties plays into memory usage; another part plays into what members you want to be "shared" across all instances.
To get a little more insight into prototypes (through understanding how new works), see What is the 'new' keyword in JavaScript?, on StackOverflow.
Here's a quote from there:
After a lot of searching, I have finally found out exactly what the
new keyword does, and it is 4 things:
It creates a new object. The type of this object, is simply object.
It sets this new object's internal, inaccessible, [[prototype]] property to be the constructor function's external, accessible,
prototype object.
It executes the constructor function, using the newly created object whenever this is mentioned.
It returns the newly created object, unless the constructor function returns a non-primitive value. In this case, that
non-primitive value will be returned.
Prototype members are shared among instances and members in the constructor function defined as this.something are instance specific.
When an instance need instance specific members (like Person.name) define it as this.name. When it can be shared (like a method sayName) define it on the prototype like: Person.prototype.sayName=function(){...
For more info on prototype and constructor functions you can check this answer.
Consider having below code
function Employee() {
this.id = "";
this.name = "";
this.gender = "";
}
function Programmer() {
this.expertise = "";
}
Programmer.prototype = new Employee();
And then I want to inherit the Programmer further to JScriptProgrammer with default value of "expertise" set to "JavaScript".
Question:
What is the diference between
function JScriptProgrammer() {
this.expertise = "JavaScript";
}
JScriptProgrammer.prototype = new Programmer();
and
function JScriptProgrammer() {
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
You can use prototype for default values of an object and it does save memory. If you don't surely shadow the property later (assign a new value for it on the instance) then all instances share the same pointer to the value.
If however you are surely going to assign a value to it then better define it in the constructor body as this.myval
Here is the tricky part of assigning default values to prototype; you have to re assign a new value to it to make an instance specific change. Object values can be manipulated by invoking functions on them or re assigning properties. When you do that then the default value for all instances change:
var Person=function(){};
Person.prototype.teeth=[0,1,2,3];
Person.prototype.legs={left:1,right:1};
var ben=new Person();
var betty=new Person();
ben.teeth.splice(2,1);//ben looses a tooth
//when ben looses a tooth like that betty looses it too
console.log(betty.teeth);//[1,2,3] poor betty
//now poor betty has an accident
betty.legs.right=0;
//looks like ben looses it too
console.log(ben.legs);//{left:1,right:0}
//I don't feel sorry for ben though because
//he knocked out betty's tooth
It is better not to initiate a new instance for inheritance, you can use Object.create or a helper function to set up inheritance without creating an instance. All about inheritance, prototype, overriding and calling super here:https://stackoverflow.com/a/16063711/1641941
the difference
function JScriptProgrammer() {
this.expertise = "JavaScript";
}
JScriptProgrammer.prototype = new Programmer();
Means when you are using JScriptProgrammer() the expertise value are already been set to "JavaScript"
but when you use
function JScriptProgrammer()
{
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
Means you set expertise value after using JScriptProgrammer()
They are the same. Second version saves memory, meaning all the children use the same instance of the function/variable.
See following example which shows why this might be required
function JScriptProgrammer() {
var tmp = "Hello";
//accessing private variables
this.sayHello = function() {
alert(tmp + " "+ this.expertise + "er");
}
}
JScriptProgrammer.prototype = new Programmer();
JScriptProgrammer.prototype.expertise = "JavaScript";
More reading
Use of 'prototype' vs. 'this' in JavaScript?
Declaring javascript object method in constructor function vs. in prototype
How to set the prototype of a JavaScript object that has already been instantiated?
In resumen:
prototype is use to inherit of existing object. For example. If you want to add a new method to Array object you can do this
Array.prototype.MyNewMethod = function()
{
alert("im bellow to array object")
}
Which means that you can to this
var array = [1,2,3];
array.MyNewMethod();//prints im bellow to array object
(read this post for more reference)
Which means that your code is doing this:
function JScriptProgrammer() {
}
function Programmer(){
this.name = "hello world";
}
JScriptProgrammer.prototype = new Programmer();// inhering from Programmers object(or lets say class)
JScriptProgrammer.prototype.expertise = "JavaScript"; // assigning a value to expertise property that belows to JScriptProgrammer class
console.log(new JScriptProgrammer())//JScriptProgrammer {name: "hello world", expertise: "JavaScript"} notice that property name that bellow to Programmer
object now is in JScriptProgrammer object as well.
here test http://jsbin.com/IgOFimi/1/edit
I am currently switching from AS3 to JavaScript.
I still have some trouble with understanding inheritance-concepts.
What I do not understand is why the following code is not working properly:
Base = function () {
this.coolVar = "great";
}
SmallControl = function () {
// Inheritance:
this.prototype = new Base();
this.prototype.constructor = SmallControl;
this.prototype.init = function(aMap) {
console.log('init');
console.log('coolVar?: ' + this.coolVar);
}
}
var foo = new SmallControl();
//foo.init(); // --> TypeError: foo.init is not a function
foo.prototype.init(); // --> works
If I put the prototype definitions outside of the "SmallControl"-Function everything works fine... but I don't understand that.
I think you want something like this:
// Create the super class
Base = function () {
this.coolVar = "great";
};
// Create the new class
SmallControl = function () {
};
// Set the prototype of SmallControl to be an instance of Base.
// This runs the Base constructor _immediately_ which sets up the variable
SmallControl.prototype = new Base();
// Add the init method to the SmallControl class
SmallControl.prototype.init = function(aMap) {
console.log('init');
console.log('coolVar?: ' + this.coolVar);
}
// Create an instance of SmallControl
var foo = new SmallControl();
foo.init();
prototype is only a meaningful property of constructors. The object's actual prototype (which is accessible in some environments as the property __proto__, but this is not portable) is set to be the constructor's prototype attribute at the time the object is constructed. Changes to the constructor's prototype (adding properties to the prototype) will be reflected in live objects, but not if you set Constructor.prototype to be a completely different object.
In your constructor, you're setting the prototype attribute of the constructed object (this). This attribute has no special meaning on something that's not a constructor function. When you set it outside of the function, you set it on the constructor function.