What sort of use cases would there be for attaching both a function AND property to your object? I haven't seen this done in Production. Is this considered bad practice?
For example:
var actor = function() {
console.log('I\'ll be back!');
}
actor.name = 'Arnold Schwarzenegger';
Function inherits from Object. Function.name is a special property that refers to the name of the function. For anonymous functions you can change the name property to whatever you want.
Is changing .name a good practice?
I would say, no. Changing the .name property doesn't achieve anything other than making things more confusing.
Your Question
attaching both a function AND property to your object
This is not what your code is doing. actor is a function, which is also an object. You can always add properties to any object except null. In fact, Function.prototype already comes with a lot of methods (properties) as defined in ES6.
Adding Properties to a Function Instance
In general, adding properties to a function instance is not a bad practice. This practice is used everywhere from creating static methods and even in jQuery (e.g. $.get):
function Person(name){
this.name = name;
}
Person.clone = function(p){
return new Person(p.name);
};
var p1 = new Person("Alex"),
p2 = Person.clone(p1); // clone p1
It is a feature of the language and you should definitely use it if it fits your purpose.
Related
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 want to understand how and why are prototypes useful in Javascript. After I thought I knew what was going on, I stumbled with the fact that a prototype is just an object and can't be "shared" by many objects in the way I thought. Let me elaborate with an example:
var SpritePrototype = {
img: null,
pos_x: 0,
pos_y: 0,
draw: function(context2d) {
/*do stuff with the canvas
using "this" to refer to
the object this method is
being called on*/
},
//Some more member functions...
}
From the concept of "objects inheriting from objects" that's usually advocated with prototype-friendly Javascript, I thought I could just do:
var player = Object.create(SpritePrototype);
But it turns out this approach is flawed, because the non-function fields will be the ones from SpritePrototype, as player's prototype is exactly SpritePrototype. That means I can't create more objects from that prototype or the non-function fields will get all mixed up.
So what's the point in Object.create, and more important, what would be the correct way to achieve what I'm trying to do? That is, how can I make "player" get a copy of the fields and inherit the functions from its prototype?
Again, I'm interested in doing things the way they're intended to be. I can always simulate inheritance by hand or skip it altogether. The point of my question is to understand prototypes and how and when they are useful, especially in my specific case.
Property values on prototypes are shared initially, but stop being shared when that property on an instance is written (assigned) to. At that moment, the instance gets its own version of the property. So it is not entirely correct to say the value is "shared". It is shared only up to the point in time at which the property on the instance is assigned to.
var SpritePrototype = {
img: 'img1'
};
var sprite1 = Object.create(SpritePrototype);
var sprite2 = Object.create(SpritePrototype);
sprite1.img = 'img2'; // does NOT affect prototype or sprite2
console.log(sprite2.img);
< "img1"
When img is referenced, its value is taken from the prototype. However, when img is written to, a new property is created on the instance to hold the new value, and used from then on.
The only way to change the property value on the prototype is to do so explicitly:
SpritePrototype.img = 'img3';
This will change img for all instances which have not yet defined their own local version of img by assigning to it.
You problem is, that you had defined "static" members in terms of object oriented design. Everything in protoype section is shared between objects. Function doesn't get actually copied to newly created object, but it is called with proper "this".
You should initialize your variables in constructor, like this
function Sprite(...) {
this.img = null;
...
}
Then for subtype you should use Object.create to create a prototype to inherit its methods, so
Player.prototype = Object.create(Sprite.prototype);
And finally, you may call parent constructor to initialize the variables
function Player(...) {
Sprite.call(this, ...);
}
PS. Constructor should be before Player.prototype assigning.
PPS. For more info see this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
The other day I was fiddling with Javascript, and I noticed that I can't write a prototype to an object within a prototype function. Like this:
var obj = function() { }
obj.prototype.First = function() {
this.prototype.Second = function() {
alert("Second Prototype");
}
}
obj.First();
obj.Second();
For some reason, the second prototype won't work and the code doesn't run. Is my syntax wrong or are there some prototype limitations that I don't know about? Thanks!
Edit:
I'm not trying to add a prototype to a prototype... that wouldn't make much sense. This is what I'm trying to do: Add two separate prototypes to obj. Prototype 2 is defined when prototype 1 is called. I thought that this would contain a reference to object, so this.prototype would be the same as obj.prototype, but it doesn't work as expected.
This is an old question, but I thought I'd add my two cents.
This code is trying to add functions on 'prototype'. However, this can only be done on the class name. What you have is a variable pointing to an anonymous class. To access the variable of an anonymous variable use 'proto'. The below is the same as your example, except, using proto it is 'successful'. Although, I don't see the benefit of using prototypes like this as the prototype added methods only apply to the anonymous instance 'obj'. http://jsbin.com/zapocamipi/edit?js,console
var obj = function() { }
obj.__proto__.First = function() {
console.log("First Prototype");
this.__proto__.Second = function() {
console.log(this);
}
}
obj.First();
obj.Second();
Maybe this could help you out understanding the role of a constructor function and the prototype.
Depending on what you're trying to do (obj, First and Second doesn't really show your intention) you could do:
A Person has Eyes. This can be done through composition.
An Employer is a Person but a Person is not necessarily an Employer (can be Client or Consultant too). This could be done through inheritance.
A Cat can move. In a Class based language Cat has to implement Movable but in JavaScript you can use mix ins and leave the implementation to the default implementation that Movable provides or override it. JavaScript does not compile time check if you do implement certain things.
If you would like to change the type of the object instance after calling a certain function then it's dangerous to meddle with the prototype because that will affect all instances of that type.
Maybe you should return an instance of another type.
var Customer = function(name) {
this.name=name || 'unknown';
};
Customer.createVipCustomer = function() {
return new VipCustomer(this);
}
var VipCustomer=function(customer){
//re use Customer constructor
Customer.call(this,customer.name);
this.isVip=true;
}
//inherit the protype defined members
VipCustomer.prototype=Object.create(Customer.prototype);
VipCustomer.prototype.constructor=VipCustomer;
VipCustomer.prototype.second=function(){
console.log('this is second');
}
var aCustomer = new Customer('Ben');
//update to VipCustomer
aCustomer = Customer.createVipCustomer(aCustomer);
aCustomer.second();
this.prototype doesn't exist.
If you want to add a property to the instance, use this.
If you want to add a property to the prototype, use Constructor.prototype.
Also, obj is a function (class), not an instance,
You want to create an instance using the new keyword, and you should name the constructor function as UpperCamelCase.
EDITED
What is the difference in doing:
var a = function(){};
a.myProperty = function(){};
Versus:
var a = function(){};
a.prototype.myProperty = function(){};
I realise this might be a silly or vague question but what do I need to understand to know the difference between the two and when to use one over the other?
Note that the question has been heavily edited since it was first posed, which is why the existing comment and answer make no sense.
All functions have prototypes. The methods attached to these prototypes are available to instances of objects created by calling the function as a constructor. So in the second example, if you write var o = new a(); then you will be able to invoke o.myProperty();.
Additionally all functions are objects, so you can set arbitrary properties directly on the function itself, as per the first example. You can also access the function from the object using o.constructor (or this.constructor from a member function). This could be used to implement the equivalent of C++ static class variables.
There is no difference. Your setting a property on an object.
Note that your second example fails because you havn't set a.prototype to a value.
Of course if you made a a function then it gets a prototype property by default.
And that .prototype property has a special property. If you invoke new someFunction then the [[Prototype]] of the return value is someFunction.prototype.
This only applies if .prototype is a property of a function. Since new only works on functions.
The below doesnt work and im struggling to work out why....
function CommentHandler() {
var Text;
}
var myCommentHandler = new CommentHandler();
myCommentHandler.prototype.SayHello = function () {
document.write('Hello World');
}
I get the error : 'myCommentHandler.prototype is undefined'
I just cant see why? I have declared a variable called myCommentHandler and copied in the object CommentHandler then Im trying to access the protoype of it and assign a function but I cant...Anyone know why?
The prototype belongs to the class, not the instance:
CommentHandler.prototype.MyFunction = ...
However you can also access the prototype via the instance's constructor property:
myObj.constructor.prototype.MyFunction = ...
This will of course add that function to every instance of your CommentHandler.
If instead you only wanted to add that function to that one instance, you'd do:
myObj.MyFunction = ...
Note that in none of these variants would it be possible for MyFunction to access your private variable Text.
This is the compromise forced by the prototype inheritance model - variables and methods must be public (e.g. this.Text) if they're to be accessed from outside, and in this case functions declared in the prototype are effectively "outside".
The alternative (using closure-scoped variables and methods) seems more natural to OO programmers, but makes inheritance much harder.
I think what you actually want here is this:
CommentHandler.prototype.SayHello = function () {
document.write('Hello World');
};
You have to use
CommentHandler.prototype.SayHello = function(){....}
You can find more about the prototype object in the following references
http://www.javascriptkit.com/javatutors/proto.shtmlhttps://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/prototypehttp://msdn.microsoft.com/en-us/magazine/cc163419.aspx
You need to prototype the class function rather than the instance. Also if you want the Text variable to be accessible outside the constructor, in the other method functions, then you need to add the this keyword.
function CommentHandler() {
this.Text = 'Hello World';
}
CommentHandler.prototype.SayHello = function () {
document.write(this.Text);
}
var myCommentHandler = new CommentHandler();
myCommentHandler.SayHello();
As a side point you could create the SayHello function inside the constructor, but this would add increased overhead to the creation of each instance of CommentHandler. Thus the prototyping method that you are using is a better option.
myCommentHandler does not have a prototype, because it is an instance. CommentHandler does have a prototype that can be modified. I am guessing you want to edit the object after initializing, and can do so like this:
myCommentHandler.SayHello = function() {
document.write('Hello World');
}
Here is a good explanation of prototypes and object oriented programming in javascript with many examples: http://mckoss.com/jscript/object.htm