Javascript - Extend method in class - javascript

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;
}

Related

Access property in class from prototype override

Not sure if my question is worded properly. But basically I have a class, but I want to write a new method for it. Say my class looks like this:
class MyClass {
constructor () {
this.someProperty = []
this.someMethod = this.someMethod.bind(this)
}
function someMethod () {
// do something
}
}
Now, because I don't have direct access to this class, I am going to create a new method using prototype
MyClass.prototype.myNewMethod = function (params) {
// do something else
// how to access someProperty? And to the bind to MyClass?
}
But now say I want to access someProperty and also want to do the bind on this new method. How can I do that?
As a matter of fact is my method creation even correct to begin with? Anyway, what I want is for it to have the same access to the this inside the class. How can I do this?
I didn't understand what you want to do but so you can access it:
class MyClass {
constructor () {
this.someProperty = [];
}
someMethod = function() {
console.log(this.someProperty);
}
}
var cc = new MyClass();
cc.someMethod();

Add method dynamically/Selective override prototype method in Flow

I have a constructor like this:
function IDBCrud(table: string): void {
...
}
IDBCrud.prototype.get = function(...) { ... }
IDBCrud.prototype.post = function(...) { ... }
And it using like this:
const accounts = new IDBCrud('Accounts');
accounts.get( ... );
accounts.create( ... );
But sometimes, I want to define method to object directly with same name as in property, so that invokes instead of prototype's method.
// Override get method for some reason
accounts.get = function( ... ) {
// Do some stuffs...
...
// Now call prototype get
return this.__proto__.get.apply(this, arguments);
}
But when I ran flow, it fails with this:
16: accounts.get = function(match, options) {
^^^ property `get`. Property not found in
16: accounts.get = function(match, options) {
^^^^^^^^^^^^ new object
Because IDBCrud doesn't have "get" property(or method). But if I just write them with empty value like this:
function IDBCrud(...): ... {
this.get = function() {};
this.create = function() {};
...
}
If should be work in that case, but if do that, I have to redefine every "get" method to invoke prototype's get method.
const accounts = new IDBCrud('accounts');
accounts.get = function() { ... }; // Override
accounts.get(); // works
const users = new IDBCrud('users');
users.get(); // Invokes users.get and it's empty function, instead of prototype.get
I don't wanna do that everytime I made IDBCrud instance, I just want to override it only it needed.
Without flow, it's not a problem, but with it, it fails.
So how do I achieve this with flow? Any advice will very appreciate it.
Override it only over the object instances where you want to achieve a different behavior:
function IDBCrud(table){
}
IDBCrud.prototype.get = function() { console.log('get1'); }
var a = new IDBCrud();
a.get(); // get1
a.get = function() { console.log('get2'); }
a.get(); // get2
var b = new IDBCrud();
b.get(); // get1
Flow was intentionally built for supporting es6 class, and it blocks me to add method in runtime for safety reasons.
Solution was simple, convert constructor to class and make new class that extends IDBCrud and override method and it's working now.

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

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

Copying Javascript getters/setters to another prototype object

// Base class
var Base = function() {
this._value = 'base';
};
Base.prototype = {
constructor: Base,
// By function
getValue: function() {
return this._value;
},
// By getter
get value() {
return this._value;
}
};
// Sub class extends Base
var Sub = function() {
this._value = 'sub';
};
Sub.prototype = {
constructor: Sub
};
// Pass over methods
Sub.prototype.getValue = Base.prototype.getValue;
Sub.prototype.value = Base.prototype.value;
// ---
var mySub = new Sub();
alert(mySub.getValue()); // Returns 'sub'
alert(mySub.value); // Returns 'undefined'
At first glance it seems that mySub.value should return the same as mySub.getValue(), but as you can see it instead returns undefined. Obviously the getter is not finding the parent scope as the Sub instance (mySub), but rather a non-existent Base instance.
Is there any way around this other than having to assign the same getters onto the new prototype?
A more modern solution is to use the Object.defineProperty since it allows getters and setters to be handled without breaking them.
Only problem is that it takes a descriptor object, so instead of manually making one, use the Object.getOwnPropertyDescriptor function to just get it for you.
var BazValue = Object.getOwnPropertyDescriptor(Base.prototype,'value');
Object.defineProperty(Sub.prototype, 'value', BazValue);
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));
Try that.
I think it would work if you assigned
Sub.prototype = new Base()
The issue is that the constructor is never run when you assign it directly from the Base.prototype.value. That value won't exist until you have an instance of the Base class (via new)
This is my typical method for extending Function to achieve inheritance:
Function.prototype.Extend = function(superClass) {
this.prototype = new superClass();
this.prototype.getSuperClass = function() {
return superClass;
};
this.getSuperClass = this.prototype.getSuperClass;
return this;
};
This will properly assign all of the parent classes methods and properties to the child 'class'.
Usage looks like
var Sub = function() {}
Sub.Extend(Base)
In addition to Alex Mcp's answer you could add new getters/setters to Sub after extending it using:
Function.prototype.addGetter = function(val,fn){
this.prototype.__defineGetter__(val,fn);
return this;
}
Function.prototype.addSetter = function(val,fn){
this.prototype.__defineSetter__(val,fn);
return this;
}
//example;
Sub.Extend(Base);
Sub.addGetter('date',function(){return +new Date;});
And to add to tylermwashburns answer: you could extend the Function prototype for that:
Function.prototype.copyGetterFrom = function(val,fromConstructor){
this.prototype.__defineGetter__(
val
,fromConstructor.prototype.__lookupGetter__(val));
return this;
}
//usage example.:
Sub.copyGetterFrom('value',Base);

Javascript inheritance and method overriding

Assume I have a class like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
From this class I created some other classes which inherit the same prototype but have some added methods. What I want to do is being able to define a load() method in the sub-classes which first calls the parent method and then execute some code. Something like:
SpecialWidget.prototype = {
load: function(args) {
super.load(args);
// specific code here
}
}
I know there's no super keyword in Javascript but there must be a way to do this.
You can simulate it like this:
SpecialWidget.prototype = {
load: function(args) {
Widget.prototype.load.call(this, args);
// specific code here
}
}
Or you can create your own super property like this:
SpecialWidget.prototype.parent = Widget.prototype;
SpecialWidget.prototype = {
load: function(args) {
this.parent.load.call(this,args);
// specific code here
}
}
so first, you set up your 'subclass' like so
function SubClass(name) {
Super.call(this);
// stuff here
}
SubClass.prototype = new SuperClass(null);
SubClass.prototype.constructor = SubClass;
and then you can do
SuperClass.prototype.theMethod.apply(this);
from within a subclass implementation to specifically invoke the super's implementation.
I don't know if this is the best solution, but you could do something like this:
function Widget() {
this.id = new Date().getTime();
}
Widget.prototype.load = function(args) {
alert( 'parent load' );
};
SpecialWidget = function(){};
// Make the prototype of SpecialWidget an instance of Widget
var proto = SpecialWidget.prototype = new Widget;
// Give the prototype a function that references the "load" from Widget
proto.parent_load = proto.load;
// Give SpecialWidget its own "load" that first calls the parent_load
proto.load = function( args ) {
this.parent_load( args );
alert( 'special load' );
};
var inst = new SpecialWidget;
inst.load();
This makes the prototype of SpecialWidget an instance of Widget so that it inherits all that Widget has.
Then it makes a reference to the load() of Widget called parent_load(), and creates its own load() that calls the parent_load() when invoked.
Since mid-2015 (ECMAScript 2015), javascript has Classes and super
Here's the link: https://262.ecma-international.org/6.0/, see section 12.3.5 (super) and 14.5 (Class definitions).
How your code would look with those changes:
class Widget() {
constructor() {
this.id = new Date().getTime();
// other fields
}
load(args) {
// do something
}
}
class SpecialWidget extends Widget {
load(args) {
super.load(args);
// specific code here
}
}
The closest I got to the previous syntax (without using class but using super) was using Object.setPrototypeOf:
// UNCHANGED
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
}
}
// slightly changed to declare SpecialWidget
function SpecialWidget() {}
// changed to define load as an method, and not a property with function as value
SpecialWidget.prototype = {
load(args) {
super.load(args);
// specific code here
}
}
// here's the key
Object.setPrototypeOf(SpecialWidget.prototype, Widget.prototype);
The declaration of load was changed because super can be used inside methods, but not functions. So, instead of load: function(args) { body }, it's simply load(args) { body }.
But, there's a caveat: with this solution, elements of SpecialWidget will not inherit the id defined as new Date().getTime(). I don't think there's a workahound (without using classes or duplicating code declaring this.id inside SpecialWidget).
It would be possible to store the old value of the load method in a closure, if you did your overriding like this:
function Widget() {
this.id = new Date().getTime();
// other fields
}
Widget.prototype = {
load: function(args) {
// do something
alert("Widget Prototype Load");
}
};
function SpecialWidget(){
};
SpecialWidget.prototype = new Widget();
(function(){
var oldLoad = SpecialWidget.prototype.load;
SpecialWidget.prototype.load = function(){
oldLoad();
alert("new Load");
};
}());
var x = new SpecialWidget();
x.load();
It works, but I'm not sure if it's the best method.
Using Simple Javascript Class:
Class.extend('Widget', {
load: function () {
alert('foo');
}
});
Widget.extend('SpecialWidget', {
load: function () {
this.super();
alert('bar');
}
});
new Widget().load(); // Alert: 'foo'
new SpecialWidget().load(); // Alert: 'foo' and 'bar'
Take a look at Simple Javascript Class Project, Simple JavaScript Inheritance and Inheritance Patterns in JavaScript.

Categories

Resources