How to "extend" an existing method of an existing class? - javascript

I have a class like this
App.Person = Ember.Object.extend({
say: function(thing) {
alert(thing);
}
});
I wish to add something to the method say , so that the method becomes
App.Person = Ember.Object.extend({
say: function(thing) {
alert(thing);
alert("Thing is said above! ");
}
});
So that
var person = App.Person.create();
person.say("Hello");
Output is Hello Thing is said above! .
I have tried to reopen the class and define the method again like
App.Person.reopen({
say: function(thing) {
alert("Thing is said above! ");
}
});
But then i am left only with Thing is said above! . Is there a way to "extend" a method?
or perform anything similar to achieve this?
also explain how to achieve the same to extend a jquery method ? , like i have jquery method binded to an DOM element and i want to extend that to add more code

I think yes. Either you call the super function into the inherited function :
// Super class
function Person() {
this.text = "Hello";
}
Person.prototype.say = function () {
alert(this.text);
}
// Inherited class
function TalkativePerson() {
Person.apply(this); // Call to the super constructor
this.extendedText = "How are you ?";
}
TalkativePerson.prototype = Object.create(Person.prototype); // Inheritance
TalkativePerson.prototype.constructor = TalkativePerson;
TalkativePerson.prototype.say = function () { // Here you redefine your method
Person.prototype.say.call(this);//And then you call the super method
// Add some stuff here like this :
alert(this.extendedText);
}
var person = new TalkativePerson();
person.say();
Or you can (in your example) directly change the value of the text like this :
function TalkativePerson2() {
this.text += ". How are you ?";
}
TalkativePerson2.prototype = new Person();
Here is a JSFiddle where you can test it.

You can call this._super(); in the extended version to have it call the original method. You can see an example of that here

Related

Javascript - Extend method in class

So I have cerated a class
function myClass()
{
}
With the method
myClass.prototype.theMethod=function()
{
}
Which is fine but I have a circumstance where I need to use this class but add extra commands to method instead of just overwriting the whole thing, if that is possible?
If you need to overrid action in certain object, then you can do the following:
var myInstance = new myClass();
myInstance.theMethod = function () {
// do additional stuff
// now call parent method:
return myClass.prototype.theMethod.apply(this, arguments);
}
For subclasses solution is almost the same, but you perform that not on instance, but on prototype of inherited "class".
Like this:
var theOldMethod = myClass.prototype.theMethod;
myClass.prototype.theMethod=function()
{
//Do stuff here
var result = theOldMethod.apply(this, arguments);
//Or here
return result;
}

Adding a property to a "Class" in JavaScript

There are no actual classes in javascript. But you have to work with what you get.
Lets take this example "Class":
var example = function (string) {
this._self = string;
}
With the above, you could do something like:
var ex = new example("Hello People."),
display = ex._self; // returns "Hello People."
I thought that by using something like example.prototype.newFun = function(){} would add a new property to that "Class". But it isn't working in my code.
Here is the full code i'm testing:
var example = function (string) {
this._self = string;//public, var like, storage
}
var showExample = new example("Hello People");
showExample.prototype.display = function (a) {//code stops here, with error "Uncaught TypeError: Cannot set property 'display' of undefined"
return a;
}
console.log(showExample._self);
console.log(showExample.display("Bye"));
What i'm trying to do is add the display function to the example function as a "public function". I might be doing something wrong.
It's not the object that has the prototype, it's the function that you use to create the object:
var example = function (string) {
this._self = string;
}
example.prototype.display = function (a) {
return a;
};
Because there's no prototype for showExample - it's only an instance of example. Try to do this: example.prototype.display = function (a) {} and it will work.
Here's a bit more on classes in JavaScript:
3 Ways to "define" classes
This lovely SO question
I like the way Classy handles this and also how classes are implemented in CoffeeScript.
You can modify to the constructor of showExample ..
ex.
showExample.constructor.prototype.display = function (a) {
return a;
}
You try to add a method to the prototype of the instance of example (showExample). The instance has no prototype. Try example.prototype.display = function() {/*...*/}; (in other words, add the method to the prototype of the constructor of showExample, that is example) and check again. After that, all instances of example 'know' the display method, or in your words, display is 'public' to all instances.
You can add the method to the instance using showExample.display = function() {/*...*/};. Using that, only showExample knows the the display method.
in your case showExample is an object of example...
use
example.prototype.display = function(a)...

Understanding Classes and Inheritance in Javascript - New Pattern

I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}

JavaScript hierarchy, why is parent variables undefined?

I wrote two classes the other day, where I needed to override and call the overridden method (getQuery).
//parent
function SimpleUser() {
this.firstName = "X";
}
SimpleUser.prototype.getQuery = function(sub) {
//solution for not getting undefined variables
var that = sub || this;
var query = "first="+that.firstName;
return query;
}
//child
function User() {
//extends
this.base = SimpleUser;
//super()
this.base();
//prints "X"
console.log(this.firstName);
this.lastName = "Y";
}
//override
User.prototype.getQuery = function() {
//call parent
var query = SimpleUser.prototype.getQuery.call(this);
query += "&last="+this.lastName;
return query;
}
//prints "first=X"
console.log(new SimpleUser().getQuery());
//prints "first=undefined&last=Y" if I don't use parameter "sub"
console.log(new User().getQuery());
When I call the method "getQuery" from the sub-class, all variables in the parent are undefined. If I call them from the constructor of the sub-class, they're fine.
I solved the problem by passing the sub-class as parameter and just checking who's asking.
Can someone please explain to me why this happens and help me to find a better solution than what I had to do with passing the sub-class itself as a parameter?
Thank you!
Javascript doesn't have classes. It only has objects. And objects inherits from their prototypes, which in turn inherits from their prototypes and so forth. If you want to learn more about making inheritance in javascript take a look at http://phrogz.net/js/classes/OOPinJS2.html. Though this is doable, if you want to mimic classes and class-inheritence in javascript I recommend using a framework designed for this such as MooTools.

Object Creation in javascript

Just for the kicks i am trying to create a simple data object in javascript. Here is the code.
var roverObject = function(){
var newRover = {};
var name;
var xCord;
var ycord;
var direction;
newRover.setName = function(newName) {
name = newName;
};
newRover.getName = function() {
return name;
};
newRover.setDirection = function(newDirection) {
direction = newDirection;
};
newRover.getDirection = function() {
return direction;
};
newRover.setXCord = function(newXCord) {
xCord = newXCord;
};
newRover.getXCord = function() {
return xCord;
};
newRover.setYCord = function(newYCord) {
yCord = newYCord;
};
newRover.getYCord = function() {
return yCord;
};
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
return newRover;
};
rover1 = new roverObject();
rover2 = new roverObject();
rover1.setName("Mars Rover");
rover1.setDirection("NORTH");
rover1.setXCord(2);
rover1.setYCord(2);
console.log(rover1.where());
console.log(rover1);
rover2.setName("Moon Rover");
rover2.setDirection("SOUTH");
rover2.setXCord(1);
rover2.setYCord(1);
console.log(rover2.where());
console.log(rover2);
There are few questions that I have around this creation.
I want to create an object where the properties/attributes of object are private and not visible to world. Am I successful in doing that? Can I really not access the object attributes?
Is there a better way to create this kind of object?
If I want to inherit this object, I should do a newObject.prototype = roverObjectwill that work? And will that make sense most of all.
Finally I have a wierd problem. Notice the last method of objet "where" which returns a concatenated string. Here I tried following code instead.
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
}();
and then did a following console.log
console.log(rover1.where);
console.log(rover2.where);
It threw following error for me:
cannot access optimized closure
Why would it say that? What am I doing wrong?
Thanks for all the help. Any review comments would be appreciated too!
Cheers
Am I successful in doing that? Can I really not access the object attributes?
Indeed. You don't have object attributes, you have local variables in the roverObject function. Local variables can't be accessed from outside, only from the functions inside the roverObject function that have a closure over them.
That you are calling roverObject as a constructor, with new roverObject, is irrelevant, as you are returning a different object from the function. Saying var rover1= roverObject() without the new would do exactly the same thing. Notably the object returned by [new] roverObject is a plain Object as you created it from {}; rover1 instanceof roverObject is false.
If you wanted instanceof to work, you would have to call with new, and use this instead of newRover in the constructor function.
If I want to inherit this object, I should do a newObject.prototype = roverObject will that work? And will that make sense most of all.
No. You currently have no allowance for prototyping. You are using a separate copy of each method for each instance of the roverObject. You can do certainly objects this way but it's a different approach than prototyping. If you wanted to make something like a subclass of roverObject in the arrangement you have now, you'd say something like:
function AdvancedRover() {
var rover= new roverObject();
rover.doResearch= function() {
return rover.where()+' and is doing advanced research';
};
return rover;
}
Note since the ‘private’ local variables in the base class constructor really are private, even the subclass cannot get at them. There's no ‘protected’.
newRover.where = function(){ ... }();
What's that trying to do? I can't get the error you do; all the above does is assigns the string with the location to where (before the setter methods have been called, so it's full of undefineds).
Is there a better way to create this kind of object?
Maybe. see this question for a discussion of class/instance strategies in JavaScript.
Q1: you can create 'private' members in javascript 'classes'. In javascript, privacy is not determined by any access specifier. Instead, access needs to be specifically instrumented. Example:
function MyClass() {
this.val = 100; // public;
var privateVal = 200;
function getVal() { return this.val; } // private method;
this.getPrivateVal = function() { // public method, accessor to private variable
return privateVal;
}
}
Object scope in javascript is governed by a queer concept called closures. AFAIK, there is no parallel concept in any other popular launguage like C+/Java etc.
While I understand what closures are, I cannot put it in words. Perhaps a demonstration will help you:
function closureDemo() {
var done=false;
function setDone() { done=true; }
doLater(setDone);
}
function doLater(func) { setTimeout(func,1000); }
closureDemo();
now, while setDone is called from within doLater, it can still access done in closureDemo, even though done is not in scope (in the conventional procedural sense).
I think you will understand more when you read this.
Q2: I can only say what I do; I don't know if it is better or not. If I wrote your code, it would look like this:
function RoverObject() {
var newRover = {}; // privates
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) {
name = newName;
};
this.getName = function() {
return name;
};
this.setDirection = function(newDirection) {
direction = newDirection;
};
// and so on...
this.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
}
var rover1 = new RoverObject();
Points to note:
capitalization of "class name"'s first letter
use of this instead of roverObject
this function is a pure constructor. it returns nothing.
Q3: if you want to do inheritance, then my method (use of this) will not work. Instead, the public methods should be a part of the prototype of RoverObject. Read this. Excellent material.
Hope that helps.
EDIT: There is a problem with the way your code is doing work. Problems:
your function does not do what its name suggests. Its name had better be createRoverObject, because that's exactly what it is doing. It is not working like a class constructor
the methods supported by your class are part of the object, but the data members are not. While this may work (and it is not, as your console.log() problem suggests), it is not a good way to implement a class in javascript. The problem here is of closures. Again, i'm unable to articulate what the problem specifically is, but I can smell it.
With regards to 4. - you are trying to log the function, not the result of calling the function. Should be console.log(rover1.where()); My guess firebug(I assume it's firebug's console.log) does not like to log function definitions.
EDIT Oh I get it, you are actually executing the where funcion when you assign rover.where. Are you trying to get what looks like a property to actually be a function? If that's the case it won't work. It will have to be a function if you want it to be evaluated when it's called.
What happens in you case where gets executed in the constructor function. At that point you are still creating the roverObject closure and hence it's too early to access it's private variables.
This is just addressing point 1 of your post.
Here's a good article on javascript private members and more:
Private Members in JavaScript
Defining your object like this gives you private members.
function RolloverObject() {
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) { name = newName; };
this.getName = function() { return name; };
this.setDirection = function(newDirection) { direction = newDirection; };
this.getDirection = function() { return direction; };
this.setXCord = function(newXCord) { xCord = newXCord; };
this.getXCord = function() { return xCord; };
this.setYCord = function(newYCord) { yCord = newYCord; };
this.getYCord = function() { return yCord; };
this.where = function() {
return "Rover :: " + name + " is at Location(" + xCord + "," + yCord + ") pointing to " + direction;
};
}
var rolloverObject = new RolloverObject();

Categories

Resources