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
Related
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)
I am working on the below task and can't find the solution. I have the constructor (Tree) and object created using it (theTree). Now I want to add new function (alter) that would change greeting value of the constructor (so of all new objects created with it) but also for existing objects. To be honest, I don't know how to get to the contructor's properties within that function. I will appreciate if you could take a look and advise where to start. This is what I got so far:
function Tree(name) {
this.name = name;
this.greeting = "Hi";
}
var theTree = new Tree("Pine");
theTree.greeting = "hello";
var alter = function(constructor, greeting) {
this.greeting = greeting;
}
Put greeting on the prototype. Remove this.greeting = from the constructor, and change the body of alter to constructor.prototype.greeting = greeting;.
However, this will not change the greeting value of instances on which it has already been set directly. No-one knows what instances have been created, unless you keep track of them yourself somehow.
var alter = function(tmpObject,greeting){
tmpObject.greeting = greeting;
console.log(tmpObject.greeting);
}
To alter function pass your constructor and greeting message.It will change.
I have a rather academic question that doesn't particularly apply to anything I'm doing, I just really want to know the answer!
Say we have a simple object definition in the global namespace as such:
TestObject = function(){};
It has a method added to it's prototype that can be instantiated into a new object itself:
TestObject.prototype.AnotherObject = function() {};
Instantiate the first object:
var myObject = new TestObject();
Now my question is this:
How does
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
Or are they exactly the same?
The difference I see is this: I could use the second method to instantiate objects within the TestObject context without knowing the name of the instantiated object itself, i.e.
TestObject.prototype.createAnObject = function() {
this.anotherProperty = new TestObject.prototype.AnotherObject();
}
And finally:
What are the implications of using a prototype method to instantiate an object of the same name? Why do this result in an infinite loop? (What actually happens inside..)
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.AnotherObject();
Yet this does not...
TestObject.AnotherObject = function() {};
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.createAnObject();
...
I have a deep desire to understand the relationships between objects here! Thank you!
The reason I ask these questions is because I want to make something like so where there is a 1:1 relationship between objects:
ClientObject = function () {
this.objectname = "a client class";
}
ClientObject.prototype.loginUser = function(name) {
this.loggedin = true;
if (typeof this.User === 'undefined') {
this.User = new ClientObject.User(name);
}
}
ClientObject.User = function (name) {
this.username = name;
}
ClientObject.User.prototype.getProfile = function() {
return 'user profile';
}
var testClient = new ClientObject();
console.log('testClient.User = ' + (typeof testClient.User)); // should not exist
testClient.loginUser('Bob'); // should login 'bob'
console.log('testClient.User = ' + (typeof testClient.User)); // should exist now Bob is logged in
console.log(testClient.User.username); // should be bob
testClient.loginUser('Tom'); // should not do anything as User object already created
console.log(testClient.User.username); // bob still
console.log(testClient.User.getProfile()); // new functionality available
I am just not sure if I'm breaking any best practises or conventions here unwittingly.
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
There's no difference at all. Remember, objects in JavaScript have a prototype chain. When you call new myObject.AnotherObject(); the engine will first check for a AnotherObject on myObject itself. Failing to find it, it will check on myObject's prototype, which it will find. The second version
myObject.myProperty = new TestObject.prototype.AnotherObject();
Just goes right to the place where AnotherObject is defined.
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.AnotherObject();
Just walk through the code. When you say: myObject.AnotherObject();, AnotherObject will be called, with this set to myObject. The first line of that will attempt to create a new property on myObject (which is this) by setting it to the result of
new TestObject.prototype.AnotherObject();
which will then re-enter the very same AnotherObject function, but this time with this set to a new object whose prototype is set to TestObject.prototype.AnotherObject's prototype. And so on ad infinitum
Finally,
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.createAnObject();
Will not cause an infinite loop, so far as I can tell, and as far as I can test: FIDDLE
Basically, createAnObject will enter with this set to myObject. Inside of which a brand new property called AnotherObject will be created on myObject, which will be set to a new invocation of the AnotherObject function you previously set up.
Note that after this call is made, the AnotherObject function will still exist, but, it will be shadowed by the AnotherObject property you just created. So now you'll never ever be able to say
var f = new myObject.AnotherObject()
Because you now have a AnotherObject property sitting right on myObject, which will be found and returned before anything on the prototype is ever checked.
Well, I mean, you could always say delete myObject.AnotherObject and remove that property from the object, which would then open you up to the AnotherObject being found on the prototype, but really, you should avoid name conflicts like this to begin with.
Regarding your last bit of code
A) Why not make User its own function?
B) Why not set up this.User = new ...() right in the ClientObject constructor function? That way you wouldn't need the undefined check
C) ClientObject should be defined as
function ClientObject(){...`
the you have it now seems to be creating an implicit global.
I don't understand in JavaScript when to use the word "prototype" vs. using simple "dot" notation without the word "prototype". Can someone look at these code blocks and help me understand when you'd want to use one over the other?
with "prototype":
function employee(name,jobtitle)
{
this.name=name;
this.jobtitle=jobtitle;
}
var fred=new employee("Fred Flintstone","Caveman");
employee.prototype.salary=null;
fred.salary=20000;
console.log(fred.salary);
without "prototype":
function employee(name,jobtitle,salary)
{
this.name=name;
this.jobtitle=jobtitle;
this.salary=salary;
}
var fred=new employee("Fred Flintstone","Caveman", 20000);
console.log(fred.salary);
JavaScript objects have a property which is a pointer to another object. This pointer is the object's prototype. Object instances by default share the same prototype:
function Employee(name){
this.name = name;
}
Employee.prototype.company = "IBM";
Employee.prototype.who = function(){
console.log("My name is", this.name, "I work for", this.company);
}
var bob = new Employee('Bob');
var jim = new Employee('Jim');
// bob and jim are seperate objects, but each is linked to the same 'prototype' object.
jim.who(); // jim doesn't have a property called 'who', so it falls back to it's 'prototype', where who exists
// My name is Jim I work for IBM
bob.who();
// My name is Bob I work for IBM
// Bob leaves IBM for Microsoft
bob.company = "Microsoft"; // bob now has a property called 'company'. The value of which is 'Microsoft', which overrides bob's prototype property of the same name.
bob.who();
// My name is Bob I work for Microsoft
Employee.prototype.company = 'Facebook';
jim.who();
// My name is Jim I work for Facebook
bob.who(); // Bob is not affected by the change.
// My name is Bob I work for Microsoft
delete bob.company;
bob.who(); // bob no longer has it's own property 'company', so like jim, it drops down to the prototype object.
// My name is Bob I work for Facebook
The issues around JS and inheritance may be complex, but the answer to your question is relatively simple. Consider this code:
function Klass() { }
var obj1 = new Klass();
var obj2 = new Klass();
Now, if you add a property to obj1, that property exists only on obj1. Likewise obj2.
If you add a property to Klass, that property likewise exists only on Klass (the function object). It doesn't affect obj1 and obj2 at all.
But if you add a property to Klass.prototype, that property will then be present on both obj1 and obj2, as well as any future objects created via new Klass. If you then change the value of the property on the prototype, the changed value will be what you see on all those objects.
You could add code inside the body of the Klass function to add properties to this; that will then cause any future Klass objects to get those properties. But each object would have its own copy - which can add up, memory-wise, especially when the properties are methods -and those copies would not be affected by future changes to the body of Klass.
ES5's Object.create almost removes the need to hassle around with .prototype anymore.
So, to pick up #Gerry's example, you can go like
var Mammal = {
walk: function() {}
};
var Dog = Object.create(Mammal, {
bark: {
value: function() {}
}
}); // create a new object which [[prototype]] refers to Mammal
Dog.walk();
Dog.bark();
The prototype object is a little tricky to understand; however this article on OOP JavaScript can help shed some light.
In a nutshell, the prototype object provides a blueprint for a 'recipient' object - all you have to do is point the recipient's prototype property at your blueprint object. Note that you can have as many recipients of a prototype blueprint object as you like (so Car and Train can both point to a common Vehicle prototype object).
You are free to define both properties and functions in a prototype object which will any recipient objects will be able to use, eg:
var vehiclePrototype = {
// A property which will be supplied to the recipient
cost: 0,
// A method which will be supplied the recipient
move: function () {
// Your prototype can refer to 'this' still.
console.log("Moving " + this.name);
};
}
You can now create a Car which makes use of the vechiclePrototype:
// Factory method for creating new car instances.
function createCar(name) {
// Define the Car's constructor function
function Car(name) {
this.name = name;
}
// Point the car's prototype at the vechiclePrototype object
Car.prototype = vechiclePrototype;
// Return a new Car instance
return new Car(name);
}
// Create a car instance and make use of the Prototype's methods and properties
var mustang = createCar(mustang);
mustang.cost = 5000;
mustang.move();
A new Train object could be created in a similar fashion:
function createTrain(whilstleSound) {
// Define the Train's constructor function
function Train(name) {
this.whilstleSound = whilstleSound;
}
// Point the train's prototype at the vechiclePrototype object
Train.prototype = vechiclePrototype;
// Return a new Train instance
return new Train(name);
}
var ic125 = new Train("pooop pooop");
ic125.move();
One of the big advantages of using Prototypical inheritance all instances of both Car and Train share the exact same move function (instead of creating multiple instances of the same function) which results in a significant memory saving if there are many instances of these objects.
Ignore new, ignore .prototype they are just confusing notions. If you really want prototypical inheritance use Object.create but most of the time inheritance is completely overkill. (prototypical inheritance should only be used as an optimization technique).
When building classes just create objects and extend them.
var Walker = {
walk: function() {}
}
var Eater = {
eat: function () {}
}
var Dog = extend({}, Eater, Walker, {
bark: function () {},
sniffBehind: function () {}
})
function dog(dogName) {
return extend({}, Dog, {
name: dogName
})
}
var steveTheDog = dog("steve")
console.log(steveTheDog.name === "steve")
Use any arbitrary arity extend function you want, _.extend, jQuery.extend, pd.extend, etc.
pd implements extend as follows
function extend(target) {
[].slice.call(arguments, 1).forEach(function(source) {
Object.getOwnPropertyNames(source).forEach(function (name) {
target[name] = source[name]
})
})
return target
}
With prototype, you can extend in a 'cleaner' way, because you are separating the logic inside your constructor function from the properties and methods that define your object.
var Mammal = function() { ... };
Mammal.prototype = {
walk: function() { ... }
};
var Dog = function() { ... };
for (var prop in Mammal.prototype) {
Dog.prototype[prop] = Mammal.prototype[prop];
}
Dog.prototype.bark = function() { ... };
However, the above without prototype could look like this:
var Mammal = function() {
this.walk = function() { ... };
};
var Dog = function() {
Mammal.apply(this);
this.bark = function() { ... };
};
This way of extending Objects is however made irrelevant by modern JavaScript libraries like Underscore.js, or could be written much cleaner with the help of for example jQuery too.
You could use the word prototype to define some functionality across the application for particular type (Array, Function, Number of custom type)
For example you can extend all arrays with property sum:
const arrayPrototype = Array.prototype
Object.defineProperty(arrayPrototype, 'sum', {
get() { return this.reduce((a,b) => a + b, 0) }
})
When you've executed the chunk of code, all arrays have the property:
console.log([1,3,-1,10].sum) // prints 13
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.