Basic Object/Prototype Syntax Issues - javascript

Can someone clear up what I'm doing wrong with my code? I'm a total newb, simply trying to experiment with how to create objects, prototypes, and what the this command refers to in the context of prototypes. However, none of my code is working on jFiddle. I know this code is completely nonsensical, but I'm just trying to find out what the document prints in various cases to get a more concrete grasp of how objects, prototypes, constructors, and the "this" keyword works. But NOTHING is showing up at all!
function Person(identity) {
this.identity = "fellow";
this.logYou = function() {
document.write('hi');
};
};
Person.prototype.logMe = function() {
document.write(this.identity);
};
var Dude = new Person("stud");
Person.logYou();
Person.logMe();
Dude.logMe();
​

function Person() {
this.identity = "fellow";
this.logYou = function() {
document.write('hi');
};
};
When you call this.identity = "fellow"; the this keyword refers the context in which the function is running.
So if you call the function in the Global scope, this refers to window object:
Person();
alert(window.identity); // fellow
And if you instanciate the function, this keyword refers to the new object:
var Dude = new Person();
alert(Dude.identity); // fellow
So the function Person has no property identity.
If you want to have some property for your function:
Person.identity = "fellow";
alert(Person.identity); // fellow

logYou and logMe are methods stored on the prototype of Person so that inheriting objects may have that function to call. You can't call logYou on Person but what you can do is call it on its child, Dude:
Dude.logYou(); // hi
Dude.logMe(); // fellow

These two lines
Person.logYou();
Person.logMe();
throw an error an couse the code to stop executing because logYou and logMe do not exist as properties of Person.
Dude.logMe() and Dude.logYou() will work, printing fellow and hi, respectively.

You cannot call
Person.logYou();
Person.logMe();
as Person has no method logYou or logMe, when you remove these two lines, your code will start working

Related

Javascript: instantiate an object with chain calling new

is it possible to instantiate an object with chain calling new on it?
I was reading a source code that did that but it was fairly confusing.
var SomeObject = function() {};
SomeObject.new.Sometask;
any direction would be appreciated.
To answer your question: yes, you can do this. I have no idea why one might want to do this, but since Javascript is so flexible, it's possible to do most things. Maybe there's an interesting use case.
You can make new a getter function on the SomeObject then when you access new return a newly instantiated object:
var SomeObject = function() {
this.name = "Test"
};
// defined new getter
Object.defineProperty(SomeObject, "new", {
get: function my_new() {
return new SomeObject()
}
});
// add Sometask
SomeObject.prototype.Sometask = function(){
console.log("name:", this.name)
return this // to allow more chaining
}
SomeObject.new.Sometask();
The OOP in your example is a little off. It looks to be a blend of traditional functional programming with JavaScript and elements of actual OOP. When talking about instantiation of objects in JavaScript, for the sake of clarity, I would refer to the syntax outlined by Mozilla here: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS
With regards to your question, you can chain a method after instantiating an object just as you can immediately retrieve a property on that newly instantiated object.
var person1 = new Person('Bob');
console.log(person1.name);
Or get the property immediately after instantiation:
console.log((new Person('Bob')).name);
The same can be done with methods:
var person2 = new Person('Bob', 23);
console.log(person2.getAge());
Or call the method immediately after instantiation:
console.log((new Person('Bob', 23)).getAge());

Javascript nested prototypes

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.

Why cant I declare a constructor instantiate an object and then access the prototype?

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

jQuery breaking "this" in constructor?

I'm working with jQuery and creating some OOP Javascript functionality. The object and its constructor has the following structure:
var zoomin = new Object();
zoomin = function() { // This is my constructor
this.someFunction();
};
zoomin.prototype = {
someFunction: function() {
// More code here
}
};
When I create an instance of zoomin (e.g. var my_zoom = new zoomin();), the call to this.someFunction() in the constructor does not work. It seems like jQuery is taking possession of "this" and this is why it is breaking.
I would really appreciate any help on how to get this to work properly.
Thanks!
Your class definition should be like this:
function zoomin() { // This is my constructor
this.someFunction();
};
For the member method definition, it should be:
zoomin.prototype.someFunction = function() {
// More code here
};
or:
$.extend(zoomin.prototype, {
someFunction : function() {
// More code here
}
});
Hope this helps. Cheers
your code is pretty messed up. you're creating a new Object, then assigning function to the same variable. so the first statement is not necessary (and not a good practice), then assigning object (with some properties) to the prototype of the zoomin object, instead of adding a property (someFunction) to it.
try to define your constructor like this:
function zoomin(){
// this is your constructor
}
zoomin.prototype.someFunction = function(){
// this is your method.
}
var zm = new zoomin();
zm.someFunction();
See the other answers as to cleaner ways to organize this. This answer just tries to address the notion of "jQuerying breaking 'this' in constructor".
A function-object (e.g. zoomin) must be invoked with new to act as a Constructor (constructors are just functions, there is nothing special without new). That is, if zoomin is used as a callback function in jQuery then this will be a particular (but arbitrary) object which is likely not a new object instance. This could give the illusion that jQuery breaks the constructor; however, it does not, because the constructor was not invoked with new and thus acts like a "normal function".
If using new fnObject then this (inside the fnOjbect function) will always be a new "fnObject" instance. There is no way for jQuery to change this, even if it tried really, really hard.
Also, the zoomin = new Object is 100% useless because the next line just assigns a new value (the constructor function-object) to zoomin :-)
Happy coding.

How does 'this' work in JavaScript?

I know there are several other posts on this topic but they still leave me confused.
I've included jQuery and everything and,
I have a simple javascript class like this example:
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph=fillKph;
}
function fillKph(){
$("#kphdiv").html(this.speed*1.61);
}
car1 = new CarConstructor();
car1.fillKph();
Now I know that that code snippet doesn't work and is not properly consturcted.
The "this" keyword there is referencing my dom element with the id of "kphdiv".
The question I have is what is the best way to handle this.
Ive seen one method where you set some variable equal to this (binding it) and then use that variable to reference your object. For example:
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph=fillKph;
}
function fillKph(){
var me=this;
$("#kphdiv").html(me.speed*1.61);
}
car1 = new CarConstructor();
car1.fillKph();
I could also make the me a global variable ... I don't know.
I was just curious if there is another/better way.
Oh boy, you are confusing quite a few things.
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph; // <-> This particular statement has no meaning.
//When you write this.fillKph without any assignment, it will be 'undefined'.
//Just because you have a function named 'fillKph' somewhere else,
//it doesn't mean it will get attached to this property.
}
Try,
var toyota = new Car();
alert(typeof toyota.fillKph); //will alert undefined.
The fillKph function is created in global scope, i.e. as property of 'Window' object.
function fillKph(){
var me=this;
$("#kphdiv").html(me.speed*1.61);
}
To fix it, you can what rezzif suggested. Your final code will look like
function Car()
{
this.speed=19; // in mph
this.make="Ford";
this.fillKph = function (){
$("#kphdiv").html(this.speed*1.61);
};
}
car1 = new Car();
car1.fillKph();
If you notice, I did not store reference to 'this' inside a local variable. Why? There is no need in this scenario. To understand more, see my detailed answer here.
If you are going to create lot of Car objects, you can define the fillKph method on the prototype.
function Car()
{
this.speed=19; // in mph
this.make="Ford";
}
Car.prototype.fillKph = function fillKph() { $("#kphdiv").html(this.speed*1.61); };
car1 = new Car();
car1.fillKph();
EDIT:
If you do something like,
function CarConstructor(){
this.speed=19; // in mph
this.make="Ford";
this.fillKph = fillKph;
}
function fillKph(){
$("#kphdiv").html(me.speed*1.61);
}
car1 = new Car();
car1.fillKph(); //This will work as expected.
But the problem is that fillKph is defined in 'Window' scope, so I can directly call it like,
fillKph(); //Calling it this way will break it as it won't get correct 'this'.
Point is,
alert(typeof fillKph); // alerts 'function' if you do it your way,
alert(typeof fillKph); // alerts 'undefined', if you do it the way I suggested, which is preferred in my opinion.
function CarConstructor(){
var _this = this;
this.speed=19; // in mph
this.make="Ford";
this.fillKph = function (){
$("#kphdiv").html(_this.speed*1.61);
};
}
car1 = new CarConstructor();
car1.fillKph();
There's completely nothing wrong with the latter method, it's perfectly fine and probably the most elegant way of doing it, it just stores a reference to the execution context in that point and time for use in another execution context where the reference points to a different object.
The confusing thing about this in javascript is it's relationship to the new operator. As you walk up the scope chain, this always refers to the last occruance of new. If need be, that means going all the way back to the window object. So if you have something like this:
function MyObject()
{
this.baz = "some value";
this.bar = function() { return this.baz; }
}
var foo = new MyObject();
alert(foo.bar());
it works as expected, because the foo variable was created with a new object/scope for the this keyword, and so the reference to this.baz points to the right place.
But then if you do this:
var foo = new MyObject();
var bar = foo.bar;
alert(bar());
expecting to call foo's bar function, you're now calling it outside of the "scope" created for foo by the new operator. Your use of this inside the bar function now looks at the window object, which doesn't have a definition for baz.
That may seem like an edge case, but it's important when working with frameworks like jQuery that create a lot of implicit objects using new or that expect you to pass functions around like variables. You have to be very careful.

Categories