In the past when creating "classes" in JavaScript, I have done it like this:
function Dog(name){
this.name=name;
this.sound = function(){
return "Wuf";
};
}
However, I just saw someone do it like this instead:
var Dog = (function () {
function Dog(name) {
this.name = name;
}
Dog.prototype.sound = function () {
return "Wuf";
};
return Dog;
})();
Can you do it both ways, or is the way I've done it wrong? In that case, why? And what exactly is the difference between the two in terms of what we end up with? In both cases we can create an object by saying:
var fido = new Dog("Fido");
fido.sound();
I hope someone will enlighten me.
There are two important differences between your way and theirs.
Wrapping in a self invoking function ((function() { ... })();)
Using the .prototype property over this. for methods.
Wrapping things in a self invoking function, then assigning the result (as defined in the return statement to a variable is called the module pattern. It's a common pattern to ensure scope is more controlled.
Using Dog.prototype.sound = function() {} is preferable to this.sound = function(). The difference is that Dog.prototype.sound is defined once for all objects with the Dog constructor, and the this.sound = function() {} is defined again for each Dog object created.
The rule of thumb is: Things that are individual to an object (usually its properties) are to be defined on this, while things that are shared to all objects of the same type (usually functions) are to be defined on the prototype.
With your code, you're creating a new function sound for every new Dog instance that's being created. Javascript's prototype avoids this by creating only a single function which all object instances share; basically classical inheritance.
In the second code you're showing that's just additionally wrapped in an IIFE, which doesn't do much in this case.
The first is the traditional method of creating a constructor. The second an immediately invoked function expression that returns a constructor. This method allows you to keep variables within the module without leaking out into the global scope which could be an issue.
And what exactly is the difference between the two in terms of what we end up with?
They both, as you've seen, have the same result. The others have talked about prototype so I won't mention it here.
The second is preferable because it takes advantage of Javascript's prototypal inheritance mechanism.
Prototypes
Javascript inheritance is a cause of confusion, but it's actually fairly simple: every object has a prototype, which is an object that we will check when we try to access a property not on the original object. The prototype will, itself, have a prototype; in a simple case, like Dog, this will probably be Object.prototype.
In both of your examples, because of how the new operator works, we will end up with a prototype chain that looks like this: fido->Dog.prototype->Object.prototype. So, if we try to look for the name property on Fido, we'll find it right there on the object. If, on the other hand, we look for the hasOwnProperty property, we'll fail to find it on Fido, fail to find it on Dog.prototype, and then reach Object.prototype, where we'll find it.
In the case of sound, your examples define it in two different places: in the first case, fido and every other dog we create will have their own copy of the function. In the second case, Dog.prototype will have a single copy of the function, which will be accessed by individual dogs when the method is called. This avoids wasting resources on storing duplicates of the sound function.
It also means that we can extend the prototype chain; maybe we want a Corgi class that inherits the sound function from Dog. In the second case, we can simply ensure that Dog.prototype is in Corgi.prototype's prototype chain; in the first, we would need to create an actual Dog and put it in the prototype chain.
Related
I've recently found an interest in the factory function pattern in JavaScript. Classes may be pretty clean, but I've found they've got their fair share of issues. (I'm not going to even talk about them because that isn't at all the purpose of this question.)
There is one major aspect of factory functions I'm not clear on however.
Correct me if I'm wrong, but in a JavaScript class my methods are placed on the resulting object's prototype so they are only ever created once. This means the constructor function used internally by the class won't be adding the methods as properties to every single new object, meaning conceptually that the methods belong to the class and not the object instance.
class Example {
constructor(message) {
this.message = message;
}
sayMessage() {
console.log(this.message);
}
}
let a = new Example("Hello!");
a.sayMessage(); // Outputs "Hello!"
console.log(Object.getOwnPropertyNames(a));
// Outputs ["message"]
Example.prototype.sayMessage = function() {
console.log(this.message + " Modified!");
};
let b = new Example("Hello!");
b.message = "Goodbye!";
b.sayMessage(); // Outputs "Goodbye! Modified!"
In the class above, sayMessage is the same function for every instance of the class. As demonstrated, it can even be changed on the prototype later, updating all existing instances of the class. I can't say for sure whether I think this is good thing, but it certainly makes sense.
However, in a factory function it seems that the object returned just has all needed methods attached to it as normal properties.
function Example(message) {
let sayMessage = function() {
console.log(this.message);
};
return {
message: message,
sayMessage: sayMessage
};
}
let a = Example("Hello!");
a.sayMessage(); // Outputs "Hello!"
console.log(Object.getOwnPropertyNames(a));
// Outputs ["message", "sayMessage"]
// Modifying the prototype is pointless because
// we haven't explicitly placed any methods there
let b = Example("Hello!");
b.message = "Goodbye!";
b.sayMessage(); // Outputs "Goodbye!"
I'd like to talk about this a bit. So first of all, is avoiding the prototype part of the whole point of using a factory function in the first place? Why would we not create a function once and instead revert to duplicating it across every instance?
I like the idea that I have more control over what I expose in the final object when I use a factory function because I can keep things private in the closure, but can I still use a prototype inheritance sort of model? Or perhaps an even better question: Would I want to? One of the main arguments I found against factory functions is that they are slower than classes in performance critical applications. Well isn't this here part of the reason? Creating a whole bunch of methods for every new object sounds like a huge waste. It sounds like the whole point of having a prototype!
A lot of questions flying around here. Let me boil it all down. I'd like to hear what the rational would be for not using a prototype (or inversely for using one) and if there is a solution that includes the best of both worlds.
Edit: When I first posted the question my second code example was creating Example instances with the new keyword, which was a typo.
One thing I don't understand with prototypes and constructor functions..
Say I have this constructor function that will create an object with a 'name' property and a 'logName' method
function MyExample(param1){
this.name = param1;
};
MyExample.prototype.logName = function(){
console.log(this.name);
}
I understand I just added a method (logName) to the constructor function's (myExample) prototype..so that when I create a new object (me) using this constructor function that object will inherit the 'name' property and the 'logName' method. The logName method will be part of new object's (me) proto property
var me = new MyExample('bob');
me.logName(); //bob
..But why not just add the logName method to the object the constructor function is creating? (not the prototype of the constructor function) Wouldn't that provide the same result? Even though 'logName' will not be part of the new object's proto property.
function MyExample(param1){
this.name = param1;
this.logName = function(){
console.log(this.name)
};
};
var me = new MyExample('bob');
me.logName(); //bob
In your second example you recreate the logName function every time you create a new instance of MyExample. If you use the MyExample's prototype then one logName method is shared across all instances of the MyExample object and context is passed around automatically.
The prototype also allows you to add a new method at a later point that can be accessed by already-existing objects of that type or globally modify a method for all objects of a type.
This question touches on the same topic if you would like more information, Advantages of using prototype, vs defining methods straight in the constructor?
The problem with creating the method in the constructor is that it isn't being shared among all instances of MyExample.
Instead, each MyExample has it's own copy of the function. It ends up taking up more memory as the number of instances goes up and if for some reason you want to modify all MyExamples at run time, you have to change every single instances function instead of modifying the prototype.
It's the difference between everyone looking at the same "copy" of Wikipedia versus everyone saving all of Wikipedia to their hard drive and reading that. It pointlessly uses up extra hard drive space and if Wikipedia is updated, everyone is wrong until they download the new version.
If for some reason you need a function which is very similar across instances but will be slightly different for each instance (for example, using closure variables) then creating methods in the constructor may be the right way to go.
Adding methods in the prototype gives your code better abstraction.
For example, since the methods are not tied to the instances, you are able to call them on non-instances which are compatible enough. Like this:
Array.prototype.slice.call({0:'a', 1:'b', length:2}); // ["a", "b"]
If you only defined your methods on the instances, it would be necessary to create an useless instance in order to borrow the method:
[].slice.call({0:'a', 1:'b', length:2}); // ["a", "b"]
Additionally, defining a method inside th constructor means that each instance will receive a different copy.
new MyExample('bob').logName === new MyExample('bob').logName // false
This means you will waste more memory.
I'm studying prototypes right now and think that I'm almost there but I'm a bit confused on one topic.
Let's say we have:
function Animal(name, gender) {
this.name = name;
this.gender = gender;
}
function Cat(species) {
this.species = species;
}
Cat.prototype.color = null;
Cat.prototype = new Animal();
My question is, why is prototype needed at all for new properties?
Why couldn't we do:
Cat.color = null;
EDIT::
All the white blocks are from a uml diagram from another SO post. I added the orange boxes to suit this example that I've provided. Does this diagram I've added to still make sense?
My main problem I believe is that I was making the function constructors and the actual prototype objects too similar when in fact they're completely different things. One's a function and one's an object.
EDIT 2
With this diagram, I'm trying to clarify how the constructor property interacts and what it is exactly connected to, and more specifically, how it affects the use of this. Any comments on the validity would help.
Good question:
Cat.color = null; sets the color only on that one Cat, if you put it on the prototype any 'Cat' you instantiate afterwards will also contain a color property.
Lets say you have something like var tabby = new Cat('feline') with the code above it without the prototype tabby won't have a color.
"Everything in Javascript is an Object"
Ever wonder why you can use .toString() on say the number 50 without having written Number.toString = function(){....?
Because it's built-into Javascript. All Number.prototypes have the .toString method. And the list goes on for Arrays, Objects, Strings, etc.
Every time you write a Number in JS, imagine (no constructor is really called) calling a Number constructor function similar to your constructor functions for Animal & Cat.
That's what constructor functions do. They create an instance of (theirname).prototype. That's why function Animal() makes something of Animal.prototype and so on.
function Animal() and function Cat() otherwise have nothing to do with Animal.prototype and Cat.prototype. If you actually made a new Animal with new Animal() and then changed the constructor, the new Animal you just made wouldn't be updated, because it was constructed before the constructor changed.
Let's say you make a Cat "Hobbes"
Then after that, when you say Cat.prototype.color = null;, you're saying all objects of Cat.prototype should have a 'null' value for color. This will update Cats you constructed before, since now when you try to find Hobbe's color, it will spit undefined since you didn't give a color to Hobbes himself in function Cat(), but then JS will backtrack to Hobbe's Cat.prototype and find that color is actually null.
Hope that helps.
Several things to remind;
A constructor function is used to instantiate new objects. If a constructor function has variables defined with a preceding this. keyword then those will be the properties of the instantiated object. The variables defined with preceding var keyword won't be a part of the instantiated object.
The objects instantiated by a constructor function will have their prototypes assigned to the constructor function's prototype hence they have direct access to the constructor function's prototype. This means they can use (share) the properties and functions within the constructor function's prototype as if they are their own.
The prototype is very useful when you think of instantiating thousands of objects from a constructor function. The unique properties of each object such as name, id, color or whatever should be defined with a preceding this. in the constructor. Such as this.name or this.color however the functionalities that they are expected to share should be defined in the constructors prototype since obviously it would be a waste of memory to reserve a room for them within each instantiated object.
Recently I read a tutorial which says if define the function like below.
function Animal() { }
On the surface, this code seems to create a function called Animal.
But with JavaScript, the full truth is slightly more complicated. What
actually happens when this code executes is that two objects are
created. The first object, called Animal, is the constructor function
itself. The second object, called Animal.prototype, has a property
called Animal.prototype.constructor, which points to Animal. Animal
has a property which points back to its prototype, Animal.prototype.
But I have little confuse about it .What about the Function object ?What is the use for the Animal object?
And If I write code like below .
var test= new Function();
and I inspected the variable test in the Developer tool of the Chrome.
I found test is nothing to do with the Function. Can someone tell me why ? thanks.
Updated
The diagram below is the objects relationship when the code is executed, please review it.
If my understanding is wrong. please correct me. thanks.
That blog post goes into a lot of detail that's interesting but unnecessarily confusing for most people most of the time.
First, let's talk about functions; forget about prototypes for a minute. When you create a function:
function Whatever() {
// ...
}
you've created an object. That is, all functions are objects, and they're constructed via the Function built-in constructor. The symbol "Whatever" in this example will have as its value a reference to that object.
Given a reference to a function, it's possible to call it:
Whatever(); // call the function
It's possible to take that value (the reference to the function object) and assign it to another variable, or pass it as a parameter to another function, or to use it just like any other value in JavaScript.
var another = Whatever;
another(); // also calls the "Whatever" function
Constructing a function via the Function constructor explicitly is something that's rarely done, but it gives you a function that's otherwise unremarkable. (In the OP, the constructed function doesn't do anything because no code was passed to the Function constructor.)
Now, things get interesting when a function is invoked as part of a new expression.
var test = new Whatever();
By using new, a new object is instantiated and associated with the "Whatever" function. The "Whatever" function is the constructor for that new object.
Every function object, whether it's ever used as a constructor or not, has an associated "prototype" object. When a function is used as a constructor, then objects it constructs (that is, objects made in new expressions that invoke the function) are implicitly associated with that prototype object.
The prototype object becomes interesting when an object property reference expression is evaluated. Object property references look like this:
obj.name
obj[ nameExpression ]
In such an expression, the property name (either the identifier used in the . expression or the value of the expression inside [ ]) is checked against the set of properties on the object directly. If the name is not the same as one of the object's properties, then the runtime consults the prototype object associated with the constructor function used to make the object.
For most code that most people write, that relationship and some of its direct implications are the only things to worry about. You don't have to fool around with the (non-standard, at this time) "proto" property of objects unless you're putting together some sort of library or framework.
Finally, it might be instructive to look at the Object.create() function and in particular the "polyfill" shown in that documentation.
Which method below is best to define a constructor prototype and why?
Method 1:
MyConstructor.prototype.myFunction1 = function(){};
MyConstructor.prototype.myFunction2 = function(){};
Method 2:
MyConstructor.prototype = {
myFunction1: function(){},
myFunction2: function(){}
};
I'm mostly concerned about speed. Thanks!
I would say there wouldn't be much of a difference. Using an object literal to assign to the Object.prototype is something you can't do if you're assigning the prototype within the constructor (which can be usefull sometimes).
Maybe you should write a little performance test using jsperf.com.
var example = new MyConstructor();
under method 1:
example.constructor === MyConstructor;
under method 2:
typeof(example.constructor) === 'undefined';
The prototype object that comes with a function has a property constructor that points back to the function. If you assign to the proprties of that object, you keep the constructor property. If you overwrite the prototype property with a new object, you lose the constructor property.
The performance difference is minimal. Because constructor is so fragile, you can't really trust it, so I don't bother to preserve it.
You should use the method 1. Using the method 2, everytime you create a new instance, you will "re-create" the methods, since they are inside the constructor.
Speaking further about the readability of your code,
method 1 is better than method 2.
Method 2 spend one more indentation. So it cause difficulty for reading codes.
Additionally, in my case,
I can't inference that whether this function is prototype method or just static member function when we see a function name part in the lower part of codes.
Personally, in conclusion,
I prefer method 2 if there not be much of a difference about performance.
Thanks!