📜 ⬆️ ⬇️

Javascript Classes: Calling Parent Class Methods

JavaScript is a very dynamic language, it has the ability to change the language for yourself and create convenient tools for further work. “Implementing classic inheritance” is just one of these tools. At the moment I can’t imagine how I would program in JS without “classes”.

For me, “Classes” is rather an approach to the design and implementation of the task. In our new project, such an approach is used in full (and I think that it is 100% justified).
This article is written as an attachment to my other article “Components in Unobtrusive JavaScript” (although, in principle, it can act as an independent text).

At the moment there is a sea of ​​implementations of "Classes in JS".
I would single out two of them: these are implementations in Prototype.js and in Base2 . In both methods, you cannot call the “other” method of the parent class (ie, you cannot call parent :: A from this.B function) - I think this is a significant drawback: it happens that you cannot perform the task without changing the approach itself.

In my implementation of “Classic inheritance in Javascript” I used a slightly “different” syntax:
// myMethod
this .myMethod.__parent(param1);


* This source code was highlighted with Source Code Highlighter .
To implement such a design, you may have had to sacrifice a little bit of performance: not all Class methods are in the prototype of the initializer function. But I know that there are much more advantages from using the approach.
')
I conditionally divided the class methods into two types:
  1. The usual methods. They are stored in the prototype of the constructor function.
  2. "Virtual" methods. Such methods, for example, __ constructor and __destructor, require the ability to call methods of the parent class. They are not stored in the prototype. And in thisObj fall into the function-initializer of the object.
Here is an example of class descriptions:
JooS.Class = JooS.Reflect( null , {
__common: new Object(),

__destroy: function () {
arguments.length ? this .__destructor.apply( this , arguments) : this .__destructor();
},
__constructor: function () {
alert( "JooS.Class::__constructor" );
},
__destructor: function () {
alert( "JooS.Class::__destructor" );
}
});


var Class1 = JooS.Reflect(JooS.Class, {
myFunction: function () {
this .__constructor.__parent();
},

__constructor: function () {
alert( "Class1::__constructor" );
this .myFunction();
},
__destructor: function () {
alert( "Class1::__destructor" );
this .__destructor.__parent();
}
});

var Obj1 = new Class1(); //
Obj1.__destroy(); //
delete Obj1; //

* This source code was highlighted with Source Code Highlighter .

Must pop 4 alert in order:
  1. "Class1 :: __ constructor"
  2. "JooS.Class :: __ constructor"
  3. "Class1 :: __ destructor"
  4. "JooS.Class :: __ destructor"
And here is the code that allows you to implement "other" inheritance:
var JooS = {
Reflect: ( function (F) {
return function (source, methods) {
if (!methods)
methods = { };
if (source) {
if (!source.prototype.__constructor)
source.prototype.__constructor = source;
F.prototype = source.prototype;
}
else
F.prototype = { constructor: source = F };

var c;
if (methods.__constructor) {
F.prototype = new F;
c = this .Virtual(F, { __constructor: methods.__constructor }).prototype.__constructor;
c.prototype = new F;
delete methods.__constructor;
}
else {
c = function () {
if ( this .__constructor)
this .__constructor.apply( this , arguments);
};
c.prototype = new F;
}
c.constructor = source;

return c.prototype.constructor = this .Virtual(c, methods);
}
})( new Function),

Virtual: ( function (hidden) {
var __index = 1;

var __extend = function (constructor, name, __self) {
var __parent = constructor.prototype[name], method;
if ( typeof __self == "function" ) {
var __selfName = __self.__name = name + "::" + __index++;
constructor.prototype[__selfName] = __self;

if (__parent && typeof __parent == "function" ) {
var __thisObj, __originalParent = __self.__parent = __parent.__self || __parent;

method = function (a1, a2, a3) {
__thisObj = this ;
__parent = __originalParent;

switch (arguments.length) { // I'm cheater. Almost...
case 0: return this [__selfName]();
case 1: return this [__selfName](a1);
case 2: return this [__selfName](a1, a2);
case 3: return this [__selfName](a1, a2, a3);
default : return __self.apply( this , arguments);
}
};

method.__parent = function (a1, a2, a3) {
var o = __parent, r;

__parent = o.__parent;
switch (arguments.length) {
case 0: r = __thisObj[o.__name](); break ;
case 1: r = __thisObj[o.__name](a1); break ;
case 2: r = __thisObj[o.__name](a1, a2); break ;
case 3: r = __thisObj[o.__name](a1, a2, a3); break ;
default : r = o.apply(__thisObj, arguments);
}
__parent = o;

return r;
};

method.__self = __self;
}
}

constructor.prototype[name] = method || __self;
};

for ( var IE = "IE" in { toString: IE })
hidden = false ;

return function (constructor, methods) {
for ( var name in methods)
__extend(constructor, name, methods[name]);

if (hidden) // thanks to Andrea Giammarchi
for ( var i=0; i<hidden.length, name = hidden[i]; i++)
if (methods.hasOwnProperty(name))
__extend(constructor, name, methods[name]);

return constructor;
};
})([ "hasOwnProperty" , "isPrototypeOf" , "propertyIsEnumerable" , "toLocaleString" , "toString" , "valueOf" ]),

Mixin: function (destination, source) {
for ( var i in source.prototype)
if (!destination.prototype[i] && i != "constructor" )
destination.prototype[i] = source.prototype[i];
},
Clone: ( function (F) {
return function (Obj) {
F.prototype = Obj || { };
return new F();
};
})( new Function),

Extend: function (destination, source) {
for ( var i in source)
destination[i] = source[i];
return destination;
}
};

* This source code was highlighted with Source Code Highlighter .

Source: https://habr.com/ru/post/40909/


All Articles