Real inheritance in JavaScript - javascript

I tried to implement prototypical inheritance between two AngularJS services and one generic service, but this seems not enough to serve my needs.
I made ChildService, SecondChildService and ParentService.
ChildService extends ParentService with prototypical inheritance
SecondChildService extends ParentService with prototypical inheritance
ParentService has a method let's call it logIt() that logs property it
ChildService implements its own version of it
SecondChildService implements its own version of it
Now I consider ParentService as the "base class", and I have a method within ParentService that calls logIt(), that is initialize(). This is only implemented in ParentService
I need to run ChildService.initialize() and see that the it of ChildService gets logged.
The same thing with SecondChildService.
Instead the ParentService logs its own version of it. The reason I believe is that prototypical inheritance is a composition implementation rather than real inheritance
Can you please propose a workaround?
Edit:
This is my parent service
angular.module('common').service('parentService', ParentService);
ParentService.$inject = [];
/* #ngInject */
function ParentService() {
'use strict';
var vm = this;
vm.it = "parent";
vm.initialize = function () {
vm.logIt();
};
vm.logIt = function () {
console.log(this.it);
};
}
This is my child service
angular.module('common').service('childService', ChildService);
ChildService.$inject = ['parentService'];
/* #ngInject */
function ChildService(parentService) {
'use strict';
var vm = this;
angular.extend(this, parentService);
vm.it = "child";
}
And this is what I get in the log when I run childService.initialize()
parent
I am expecting to get child instead

I can't reproduce your problem. Inheritance seems to work correctly in the following example:
class Main {
do_it() {
console.log("Main do_it");
this.it();
}
it() {
console.log("Main it executed");
}
}
class A extends Main {
it() {
console.log("A it executed");
}
}
var a = new A;
a.do_it();
console.log("Done");
The do_it method that is defined in the Main class correctly calls the it method of the extended class which has overridden the it method of the parent class.

The problem is in ParentService. I am using vm.logIt, while I should be using this.logIt in order to get the it from the child service scope. Contrary to standard inheritance, it seems that in prototypical inheritance the logIt() function exists twice, once in the ParentService and once in the ChildService (inherited from parent). With this.logIt() you can call it from the child and it actually gets the it from the child, while with vm.logIt() you call it from the parent where it gets the it from. It is a matter of scope.
This is the correct implementation of ParentService:
angular.module('common').service('parentService', ParentService);
ParentService.$inject = [];
/* #ngInject */
function ParentService() {
'use strict';
var vm = this;
vm.it = "parent";
vm.initialize = function () {
this.logIt(); // <-- this changed
};
vm.logIt = function () {
console.log(this.it);
};
}

Related

NodeJS EventEmitter not being called in event in a class

When I Register an function as an event, the emit inside said function does not get called. The function it self is called (as tested by log). Now when I register the event using method 2, it works. Why is this?
Method 1 (Does not call event):
"use strict";
const EventEmitter = require("events");
class DiscordBot extends EventEmitter{
constructor(key){
super();
}
startBot(){
var self = this;
this.bot.on("ready",self.botReady);
}
botReady(){
var self = this;
self.emit("Bot_Ready");
console.log("TESD");
}
}
Method 2 (works):
"use strict";
const EventEmitter = require("events");
class DiscordBot extends EventEmitter{
constructor(key){
super();
}
startBot(){
var self = this;
this.bot.on("ready",function () {
self.botReady();
});
}
botReady(){
var self = this;
self.emit("Bot_Ready");
console.log("TESD");
}
}
Register:
bot.on("Bot_Ready", function(){
console.log('this happens ');
});
This creates a closure:
this.bot.on("ready",function () {
self.botReady();
});
Method 1 doesn't:
startBot(){
var self = this;
this.bot.on("ready",self.botReady);
}
From the MDN link above:
A closure is a special kind of object that combines two things: a
function, and the environment in which that function was created. The
environment consists of any local variables that were in-scope at the
time that the closure was created.
Here is another great link that might help explain:
How do JavaScript closures work?
Note this part:
In JavaScript, if you use the function keyword inside another
function, you are creating a closure.
"Maybe you lose context and you need to use arrow function like this this.bot.on("ready", () => this.botReady());" - #yurzui
Works like a charm.

Class that depends on its closure

Because of angular factories, I am thinking about using a class that uses some methods that are on its closure as if they were private methods.
This is not 100% classical inheritance nor revealing pattern, so I'm not sure if this is correct or not. Here is a small example:
myClass = (function() {
function privateMethod (stuff) { return something }
function TheClass () { this.someValue = 'Hello'}
TheClass.prototype.someMethod = function () { return privateMethod(this.someValue)}
return TheClass
}());
And then do something like
instance = new myClass()
I think this works fine for helper functions or private methods that do not change the values of the instantiated object. Using private "variables" may be useful for singelton classes or maybe fixed values.
Is there any problem with this implementation?
That's typically fine to do and its essential that most classes depend on their closure. Usually your class will be in its own file - its own module. If you are using a module loader (I hope you are), then closure is already implied and the methods are already "private" when defined like this:
// Begin MyClass.js
function privateMethod (stuff) { return something }
function TheClass () { this.someValue = 'Hello'}
TheClass.prototype.someMethod = function () { return privateMethod(this.someValue)}
// depending on which module loader you are using
return TheClass;
module.exports = TheClass;
export default TheClass;

How use prototypical inheritance in controllers in node.js

I need make one Super Function inherit the this of other function and make this other function inherit the methods from the Super Function, this is possible?
Explanation:
I have my BookingController and I want make the Controller function inherit the this.ME property:
BookingController.js:
var Controller = require('../api/Controller');
function BookingController() {
Controller.call(this);
this.ME = 'something here';
}
BookingController.prototype = new Controller;
BookingController.constructor = BookingController;
Controller.js:
function Controller() {
console.log(this); // EMPTY
};
Controller.prototype.myMethod = function() {
// Should work if BookingController try to access.
}
But nothing happens, there is no error and the BookingController can't find my myMethod and my Controller can't my this.ME
You use a bit wrong inheritance model. I suggest you to use something like
BookingController.prototype = Object.create(Controller.prototype);
BookingController.prototype.constructor = BookingController;

Access TypeScript functions from JavaScript

I want to use TypeScript with jsTree. How can I call the setCurrentNode function in the bound jsTree function?
class MyController {
thescope: any;
static $inject = ['$scope'];
constructor($scope) {
$scope.vm = this;
this.thescope = $scope;
(<any>$("#demo2")).jstree({
.bind("select_node.jstree", function (e, data) {
// how can I call setCurrentNode(data) here?
}
});
}
setCurrentNode(node: any): any {
... // do Stuff in this typescript function
}
}
Solution:
(<any>$("#demo2")).jstree({
.bind("select_node.jstree", this.setCurrentNode.bind(this) )
}
public setCurrentNode(e:any,data: any): any {
...
}
I'm not completely sure, so please correct me if I'm wrong, but wouldn't the use of the lamba expression solve this problem as well?
As follows:
class MyController {
thescope: any;
static $inject = ['$scope'];
constructor($scope) {
$scope.vm = this;
this.thescope = $scope;
(<any>$("#demo2")).jstree({
.bind("select_node.jstree", (e, data) => {
this.setCurrentNode(e, data);
}
});
}
setCurrentNode(e: any, node: any): any {
... // do Stuff in this typescript function
}
}
The lambda (=>) expression will make sure the function is executed in the same scope as the scope you're defining it in. If you'd look at the compiled JavaScript code you'll see he will keep a reference to the constructor scope and will call setCurrentNode on that scope. Simplified example:
var _this = this;
$("#demo2").jstree({
.bind("select_node.jstree", (e, data) => {
_this.setCurrentNode(e, data);
});
I believe this would solve your problem?
On a side note, you should look for a jsTree definition file or at least add a stub declaration yourself so you don't need to cast JQuery to any. Just my 2cts, it looks ugly to me.
As per Anzeo's suggestion to prevent the need for casting $ to any the following is all you need to get you started :
interface JQuery{
jstree:Function;
}
What it happens is that the inner jsTree callback is overwriting the this initial reference to the instance object.
There are two safe ways to solve this:
1- By the use of the arrow function as pointed by #Anzeo, which I don't recommend and I never use since if you need to have another nested callback then you can have a this reference to the innermost event object.
2- By caching the this reference to the instance object like:
class MyController {
thescope: any;
static $inject = ['$scope'];
constructor($scope) {
// Caching the reference for using it in the inner callbacks.
var self = this;
$scope.vm = this;
this.thescope = $scope;
(<any>$("#demo2")).jstree({
.bind("select_node.jstree", function (e, data) {
// Call to the instance method here!
self.setCurrentNode(/*Node params here*/);
}
});
}
setCurrentNode(node: any): any {
... // do Stuff in this typescript function
}
}
I recommend you to stick with 2 since it will work though any nesting level and you can have the this in each nested callback pointing to the right event object.
See Javascript 'this' overwriting in Z combinator and every other recursive function for more references since the problem is the same as here.

Is it possible to let Angularjs work with prototype methods and variables

You know, in angularjs, most of logical are based on $scope:
function Ctrl($scope) {
$scope.name = "Freewind";
$scope.hello = function() {
alert($scope.name);
}
$scope.method1 = function() {}
$scope.method2 = function() {}
$scope.method3 = function() {}
$scope.method4 = function() {}
$scope.method5 = function() {}
}
Now I'm using haxe to generate angularjs code, it works if my code is:
class Ctrl {
public function new(scope:Scope) {
scope.name = "Freewind";
scope.hello = function() {
alert(scope.name);
}
scope.method1 = function() {}
scope.method2 = function() {}
scope.method3 = function() {}
scope.method4 = function() {}
scope.method5 = function() {}
}
}
typedef Scope = {
name:String,
hello:Void->Void,
method1: Void->Void,
method2: Void->Void,
method3: Void->Void,
method4: Void->Void,
method5: Void->Void
}
But I want to be benefited from haxe's class system(the code may be simpler and clearer), to declare it like:
class Scope {
public var name:String;
public function hello() {}
public function method1() {}
public function method2() {}
public function method3() {}
public function method4() {}
public function method5() {}
}
Then find a way to associate the Scope class with the $scope of angularjs.
But the generated Scope from haxe are using prototypes:
Scope = function();
Scope.prototype.name = "something";
Scope.prototype.hello = function() {}
Scope.prototype.method1 = function() {}
Scope.prototype.method2 = function() {}
Scope.prototype.method3 = function() {}
Scope.prototype.method4 = function() {}
Scope.prototype.method5 = function() {}
In this case, I can't find a solution to let angularjs work with it.
Is it possible to let angularjs to work with prototypes, so it can work with haxe class system (also other languages like coffeescript/typescript which have class support)?
For the sake of having an actual answer to this question, one should mention that now this library solves the problem: https://github.com/freewind/HaxeAngularSupport ;)
Scope's constructor is declared within a closure, so you don't have easy access to it... BUT(!) JavaScript has the constructor available to you right off of any existing object.
Theoretically, you could get the $rootScope's constructor, alter it's prototype, and that should alter any subsequently created Scopes. You'd probably want to do this in the .run() or .config() on your application module, however.
app.run(function($rootScope) {
$rootScope.constructor.prototype.foo = 'Set from prototype';
});
It works and here's the plunker.
HOWEVER: You probably don't need to do this. The only reason I could think of that you might need to do this is in some edge-case where you needed to make sure some function or property was available on a scope, even if it was an isolated scope (as was the one in the directive in the plunker I linked).
Because there is scope inheritance, and because you have $rootScope to use, I can't really think of any valid reason to need to alter Scope via prototyping.

Categories

Resources