Reputation: 24305
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);
Upvotes: 14
Views: 6381
Reputation: 1265
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
Upvotes: 0
Reputation: 95252
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
.
Upvotes: 9
Reputation: 169391
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
}
Upvotes: 1
Reputation: 5231
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
Upvotes: 11
Reputation: 6209
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.
Upvotes: 1
Reputation: 6012
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.
Upvotes: 0
Reputation: 235992
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();
Upvotes: 3