I have an app.js with this code:
var addnote = (title,body) => { /* enter code here */ }
module.exports = {addnote};
Can I add another addnotes function with different parameters to that file?
Function overloading in JavaScript does not exist like in other programming languages such as C# and Java.
What you should be looking to do is pass an object as a parameter that has properties attached and filter them out there..
You could call different functions from your little 'mapping function' just implement the logic there if it isn't big (to keep the code clear).
function foo(parameters){
var title = parameters.title;
var body = parameters.body;
if(parameters.extraProperty){
// oh we have extraProperty passed in too, run a different function?
bar(title, body, parameters.extraProperty); // ??
}
}
foo({title: 'Title', body: 'Body', extraProperty: 'This is extra...'});
If this is your own custom module, you can use the concept of function overriding, where each child class can have its own way to handle something and also have a default way to do things.
class Parent {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`);
}
}
class Child1 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hey there ${this.name}. This is Child 1`);
}
}
class Child2 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hi there ${this.name}. This is Child 2`);
}
}
const o1 = new Child1('Foo')
const o2 = new Child2('Foo')
o1.greet();
o2.greet();
But if you are trying to override a function in an external module(You do not have access to that code, like a library), my suggestion is to create a wrapper and add functionality there.
Related
some times code says it best. In below example code in Chain.add I have the function name and vars fed in to it. But I am trying to reference the object that the function is associated with. How can I do this
class Chainable {
constructor(...values) {
this._chainableConstruct={
name: this.constructor.name,
values
};
}
}
class Chain {
constructor() {
this.data=[];
}
add(func,vars) {
console.log(func.name); //returns fun
console.log(...vars); //returns test 45
console.log(func.parent); //return undefined want object t from line 28
}
}
class Test extends Chainable {
fun() {
console.log("fun");
}
}
let t=new Test();
let c=new Chain();
c.add(t.fun,["test",45]);
Out of the box, you can't. Furthermore, you can set property values of multiple objects with the same value, so the same function object might have multiple "parents".
I have a child class which extends parent class. I also want child class to be able to emit events. Examples I found were extending EventEmitter. But JS does not allow multiple inheritance. I tried to implement it via mixin but not sure how to do without converting my parent class to a mixin.
Example
Say there is a base class for vehicles
all vehicles move and some can emit events when they move
class Vehicle {
constructor(name) { this.name = name }
move() { console.log(this.name, 'Moved'); }
}
class Car extends Vehicle {
constructor() { super('Ford'); }
move() {
super.move();
this.engineSound();
}
engineSound() {
console.log("Vroooom!");
}
// some other car related properties
}
class Ambulance extends Vehicle { // want to extend EventEmitter aswell
constructor() { super('Ambulance1'); }
move() {
super.move();
// emit moved event here
}
}
let normalVehicle = new Vehicle('Normal');
normalVehicle.move();
let car = new Car();
car.move();
let ambulance = new Ambulance();
// Listen for moving ambulance here
// ambulance.on('moved', () => { console.log('Ambulance coming') });
ambulance.move();
But to emit events docs suggest extending EventEmitter but JS does not support extending multiple classes.
Saw few examples which were using Object.assign but not sure how that can be applied here.
es6 class syntax doesn't support multiple inheritance at all. You can try weird trickery if you convert all classes to es5 constructor functions and then use things like Object.assign. But the best approach would be to use composition over inheritance.
OOP is used to try and mimic real world objects, so in real world terms it also doesn't make sense for an ambulance to be itself an event emitter.
However, using a composition approach, it makes sense for an ambulance to have an event emitter, like a radio or other such transmission device:
class Ambulance extends Vehicle {
#radio = new EventEmitter();
constructor() {
super("Ambulance");
}
emit(event) { this.#radio.emit(event) }
on(event, handler) { this.#radio.on(event, handler) }
move() {
super.move();
this.emit("moved");
}
}
let ambulance = new Ambulance();
ambulance.on('moved', () => { console.log('Ambulance coming') });
ambulance.move();
composition example
Note that the radio is private (using the new JS private fields feature), and I only supply a facade for the exact functionality I want the ambulance users to have, in this case 'on' and 'emit'.
With that said...
Lets get crazy and actually answer your question! Again, this will require to use es5 constructor functions:
// Base class - no inheritance
var Vehicle = (function () {
function Vehicle(name) {
this.name = name;
}
Vehicle.prototype.move = function () {
return this.name + " Moved\n";
};
return Vehicle;
})();
// Derived from Vehicle - regular inheritance from a single object
var Car = (function (_super) {
function Car() {
// Calling super() in constructor
_super.call(this, "Ford");
}
// extend Vehicle
Car.prototype = Object.create(Vehicle.prototype);
// bring back Car's constructor, because last step overrid it
Object.defineProperty(Car.prototype, "constructor", {
value: Car,
enumerable: false,
writable: true,
configurable: true
});
Car.prototype.move = function () {
return _super.prototype.move.call(this) + this.engineSound();
};
Car.prototype.engineSound = function () {
return "Vroooom!\n";
};
return Car;
})(Vehicle);
// Derived from Vehicle and EventEmitter - multiple inheritance!
var Ambulance = (function (_superVehicle, _superEventEmitter) {
function Ambulance() {
_superVehicle.call(this, "Ambulance");
_superEventEmitter.call(this);
}
// Create joint prototype using Object.assign
var jointPrototype = Object.assign(
{},
_superEventEmitter.prototype,
_superVehicle.prototype
);
// Connecting Ambulance to prototype chain
Ambulance.prototype = Object.create(jointPrototype);
// restore Ambulance's constructor
Object.defineProperty(Ambulance.prototype, "constructor", {
value: Ambulance,
enumerable: false,
writable: true,
configurable: true
});
Ambulance.prototype.move = function () {
this.emit("moved");
return _superVehicle.prototype.move.call(this);
};
return Ambulance;
})(Vehicle, EventEmitter);
es5 multiple inheritance example
I'm trying to write a simple Discord bot in TypeScript, using discord.js and clime.
I'm running into an issue where I'm trying to access an object property of a context object that I pass around, but it's always null. When I check the properties using either vscode's debugger or console.log, the object seems to have all of the properties that I would expect, except they're all nested one layer too deep.
export class DiscordCommandContext extends Context {
public message:Message;
public client:Client;
constructor (options:ContextOptions, message:Message, client:Client) {
super(options);
this.message = message;
this.client = client;
}
}
When I try accessing it the message property, it's always falsy (if block is skipped over).
if (context.message.guild) {
var settings = await repo.getRealmSettings(+context.message.guild.id);
if (key) {
embed.fields.push({name:key,value:settings[key]});
} else {
Object.keys(settings).forEach(property => {
embed.fields.push({name:property,value:settings[property]});
});
}
}
But in the console, I see this:
DiscordCommandContext appears to have nested "message" objects, one of the wrong type
I cannot access context.message.message, I get "Property 'message' does not exist on type 'Message'", which is as I would expect.
EDIT 1
My instantiation code looked like this:
var options:ContextOptions = {
commands: argArr,
cwd: ""
};
var context = new DiscordCommandContext(options, this.message, this.client );
Where argArr is a split string passed into the method and both this.message and this.client are populated in the constructor of the calling class (none are null)
I managed to get DiscordCommandContext to function properly by changing it to this:
export class DiscordCommandContext extends Context {
public message:Message;
public client:Client;
public realmSettings: RealmSettings;
constructor (options:ContextOptions, contextExtension:DiscordCommandContextValues) {
super(options);
this.message = contextExtension.message;
this.client = contextExtension.client;
this.realmSettings = contextExtension.realmSettings
}
}
export interface DiscordCommandContextValues {
message:Message;
client:Client;
realmSettings: RealmSettings;
}
And calling it like this:
var context = new DiscordCommandContext(options, {message:this.message, client:this.client, realmSettings: settings} );
I'm not sure if that's the right way or not... but it works.
How can i use class instance in another class like a pointer in C++ to class instance functions?
Example:
class A {
constructor()
{
this.block = [];
}
method()
{
return this.blocks.length;
}
}
another class:
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method(); // here i'm getting cannot get length of undefined
}
}
If i'm trying to to like that i'm getting problems to call it
You can try this. Here, when creating B class's instance I give into it an A class's instance as argument. Then inside B we can call A instance's methods, and access its properties.
Also, as #ViaTech posted you can use static methods to access them without needing to initialize an object of the class. That is what static methods is. Refer Static Methods
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method();
}
}
class A {
constructor()
{
}
method()
{
console.log("A's method");
}
}
var a = new A();
var b = new B(a);
b.method(); // A's method
You can easily do this in JS by calling a static method like so:
class A {
static write(){ //static method
console.log("Called write from A");
}
}
class B {
doIt(){
A.write();
}
}
let b = new B();
b.doIt();
Option 2, you instantiate the class in the constructor of the other like so:
class A {
write(){
console.log("Non-static write() called from class A");
}
}
class B {
constructor() {
this.a = new A();
}
doIt(){
this.a.write();
}
}
let b = new B();
b.doIt();
There are a few ways:
I accidentally switched between PHP and Javascript, but the principles are the same for both)
Use static functions:
Normally, you have a this in the class. Say you have this code:
class Car {
let color;
public function setColor(newColor){ this.color = newColor;}
}
let car = new Car();
car->setColor('green')`
The setColor function's this refers to that car. You can make let anotherCar = new Car(), then when you do anotherCar->setColor('red') you only change that car, not the first one. Simplistic: You can create multiple instances.
If you do not need that, but need the class once, you can make it static. A simple way to explain would be "you have a collection of seperate functions, just put into a wrapping class (which doesn't do a lot really)". For instance, you might have some sanatizing methods:
class Sanitize {
static function makeHtmlSave(input){
return doYourMagicHere(input);
}
static function removeXssCode(input){
return doMoreMagicHere(input);
}
}
This way, you can reuse it multiple times. If you want to use it, you do Sanitize::makeHtmlSave(someCode) where you need it. There isn't a Sanitize thing, it's just a wrapper to access the frunctions inside it.
Use extend:
You can extend a class. Say you have a generic class Vehicle, which has some properties (eg a motor, numberWeels, color) and you can extend that with more specific classes:
class Vehicle {
let color;
public function setColor(newColor){ this.color = newColor}
}
class Car extends Vehicle {
let hasAirco = false;
public function hasAirco(newValue){ this.hasAirco = newValue};
}
If you do let car = new Car(), you get a Car object, that extends/enlarges/complements the Vehicle class, so you can use both its (public) functions. Internally, Car can use the functions of Vehicle too.
Just pass it
class One {
// some stuff
}
class Two{
let otherObject;
construct(givenObject){
this.otherObject = givenObject;
}
}
You can now do this let a = new One(); let b = new Two(a);. You can not use the functions of One inside Two, but you can still use a->doSomething(). This solution feels like the easiest, but it almost never is. Classes/objects are tricky stuff, but I've rarely uses this solutions. There are use cases, but often it's a bad smell indicator.
I'm learning TypeScript and have the following class:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(getCertificate)
.fail(somethingWrong);
function getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
}
As you can see on the above code, the first call to this refers to my class DetailDriver. That's good. The second call to this (inside getCertificate) refers to any. That's not what I need. I need to refer to my class DetailDriver.
How to proceed?
Thanks.
Well,
According to section 4.9.2 of the TypeScript Language Specification you should use fat arrow syntax to preserve the scoping for this.
return promise
.then(() => return.this.id;)
.fail(somethingWrong);
Then the this keyword is properly determined to be a Driver.
For reference, you could also just do:
class SomeClass {
public someMethod() {
// Do something
}
public anotherMethod() {
var that = this; // Reference the class instance
function someFunction () {
that.someMethod();
}
}
}
You could refactor to something like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(this.getCertificate.bind(this)) // <- important part
.fail(somethingWrong);
}
// new method function here
private getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
Using the function keyword anywhere in your class will make any reference to this keyword refer to that function rather than the outer class. Generally, you want to avoid defining functions inside of classes, unless you use the "fat arrow" syntax. That would look like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(() => { // <- important part
var id = this.driver.id(); // this refers to any
return ...
})
.fail(somethingWrong);
}
}