Overidding library function in es6 - javascript

I'm trying to override specific function in a library.
In my case, I'm trying to override some functions on Framework7. The library simply has class called Framework7, in non ES6 javascript, creating instance of application would look like this:
var app = new Framework7();
so I assume it's extendable, so here my code to extends it:
export class Application extends Framework7 {
constructor(options) {
super(options);
}
}
the code run fine, however, when I try to override one of the function, let say showPreloader, the function itself is never called
export class Application extends Framework7 {
constructor(options) {
super(options);
}
showPreloader(title) {
console.log('this not printed :(');
super(title); // this is not called as well
// but showPreloader() from Framework7 still called
}
}
I also try different approach to override it, i come with a solution like this:
export class Application extends Framework7 {
constructor(options) {
super(options);
this.showPreloader = (title) => {
console.log('print me!'); // printed! :D
super(); // oh, wait! cannot call super from here! :(
}
}
}
However, it looks a bit ugly and I cannot call super from there.
Is there any workaround so I can override a function from library and calling the base function via super (or anything?)

I assume it's extendable
Don't. Read the docs, ask the authors, or read the source yourself.
In your case, the library you've chosen doesn't exactly follow best practises, it just installs its methods directly on the app "instance". It's a factory function, not a constructor.
Is there any workaround so I can override a function from library and calling the base function?
Yes, by storing the original method in a variable before overwriting it. You then can call it using .call(this) (like inheritance was done in ES5).
…
const original = this.showPreloader;
this.showPreloader = (title) => {
console.log('print me!'); // printed! :D
original.call(this, title);
}
However, that's no fun, especially since it's not just a few instance-specific methods but actually all of them. So you'd better drop ES6 class syntax and "subclassing" here, and use a parasitical inheritance approach instead:
function MyFramework7(options) {
const app = new Framework7(options);
const {showPreloader, …} = app; // all the original methods
… // mess with the object to your liking
return app;
}
Or maybe you don't even need to wrap it in a function, as app is a singleton I guess.

Related

Undertanding JavaScript methods

I am pretty new to JavaScript, coming from a Java background. I was just playing around with the NodeJS ("type": "module") Express framework but got between two types of ways for writing the methods in JS.
Below are the examples (check comments inline).
Type 1:
main.js
const method1 = () => {
...
method2();
...
};
const method2 = () => {
// this is not exported, so it works as a private method and won't be accessible in other JS files
...
};
.
.
.
// likewise there can be many other methods here
export { method1 }; // export other methods as well
Then, I can use the method1 (cannot use method2 as it is not exported) in any other JS file like below:
test.js
import { method1 } from './main.js';
method1();
Type 2:
main.js
class Main {
method1() {
...
method2();
...
}
#method2() {
// this is a private method, so won't be accessible outside of this class
...
}
// likewise other methods here
}
const main = new Main();
export default main;
Then, I can use this class instance in any other JS file like below:
test.js
import main from './main.js';
main.method1();
I want to know what is the difference between these two, when to use which, and which is better.
Both approaches work fine, but Type 2 is somewhat weird because you're using a class only to keep something from being exported.
Classes are usually used to group together data (properties on the instance of the class) with methods that operate on that data. For a silly example:
class NumberMultiplier {
constructor(num) {
this.num = num;
}
multiply(mult) {
return this.num * mult;
}
}
const n = new NumberMultiplier(5);
console.log(n.multiply(10));
Above, there is data (this.num), and there's also a method that operates on the data (multiply).
But in your case, you don't look to have instance data - you only want to group functions together, there's not really a reason to use a class. You can consider defining the functions individually - as you did in the first snippet - or you could use a plain object that gets exported, with only the properties you need:
const method2 = () => {
};
export default {
method1() {
method2();
}
};
If you do have persistent data and want to put it on the class instance, using a class and # private methods is a possibility (creating a single instance with new and then exporting that instance is an example of a singleton).
A potential issue to be aware of is that if you use export default with an object, there's no way to extract a single property of the export when importing in a single line. That is, if you only have a default export, you can't do something like
import { method1 } from './main.js'.default;
You could only do
import theObj from './main.js';
const { method1 } = theObj;
which some would consider to look a bit ugly. Having independent named exports can make it a bit easier for the consumers of a module to import only what they need into standalone identifiers, in a single line.
Classes in JS, unlike your familiarity in Java, are rarely used when not explicitly necessary. Nevertheless, there are situations where OOP in JS could be very useful.
Basically, the first method (Type 1) is what you're going to be using/seeing 99% of the time if you're doing just general JS programming such as front-end websites or apps.
If you're i.e. making a game however, you could use OOP to have better control over the different characters/object in your game.
In terms of back-end or on an infrastructural level, it really depends. You could perfectly use classes (Type 2) if you're following the MVC design pattern, but is again optional.
In the end, it comes down to your own design choice(s). You could go for FP (T1) or OOP (T2) whenever you like in JS, although there are some 'industry standards' for certain scenarios to decide when to use which.
It actually depends on what you are exporting. The type 1 is more appropriate if you export only one or a few objects. With type 1, you can export any primitive type variables or objects and can be used straightaway in the main.js.
However, if you want to export many objects and/or variables, then type 2 makes sense. With type 2, all exports are stored in an object, so you have to access them using this object.
Performance-wise both are same.

Using class object from diffrent class

I’m having type script class which expose some service list
I’ve defined a property that should have reference to the ServiceCatalog class like following:
export default class myGenerator extends Generator {
private svcat: ServiceCatalog | undefined;
// and here I’ve initilzied the property
await this.getSvc();
// here I created some function the return service instances
private async getSvc() {
this.svcat = new ServiceCatalog();
await this.svcat.getServiceInstances();
}
// and here I’ve additional code which use it
this.svcat.values ….
My question is there Is a better/cleaner way of doing the in javascript/typescript ?
maybe not using the this keyword...
And also maybe a better code for testing (unit-test) ...
The way you are doing today, it is very hard to test. Why is that? Well, because if you want to isolate your Generator class from your ServiceCatalog, you will have a hard time.
What I suggest, like the colleague above, is to have the ServiceCatalog coming by customer BUT have a default value.
class MyGenerator extends Generator {
constructor(private svCat: ServiceCatalog = new ServiceCatalog()) {
super();
}
}
This way you can use it normally like
new MyGenerator()
or for testing
new MyGenerator(myFakeServiceCatalog)
Inject the Service into your myGenerator class.
Add this to your constructor:
constructor(private svcat:ServiceCatalog) {}
You can now access the injected Service using
await this.svcat.getServiceInstances();
There is no need to add a property (your svcat:ServiceCatalog|undefined part) for the service.
"this" is needed a lot in java/type-script since it refers to the current class.

Class properties for react lifecycle methods

Can I write React lifecycle methods as class properties?
I've been using class properties for a while as I like the fact that I no longer have to manually bind my methods, but I'd like to keep some consistency across my components and I'm wondering if there is any drawback on writing the React lifecycle methods as class properties
import React, { Component } from 'react';
class MyComponent extends Component {
render = () => {
return (
<div>Foo Bar</div>
);
}
}
export default MyComponent;
For example, is the context of this class property affected compared to the context in an equivalent method. Given that the render method in the above code is written as an arrow function, this concern seems relevant.
In a way, the true answer depends on your build pipeline and what the resulting Javascript output looks like. There are two primary possibilities:
Input Code
Let's start by saying you are writing the following before going through any sort of pipeline transformations (babel, typescript, etc):
class Test {
test = () => { console.log('test'); };
}
Output as class member variable.
In one possible world, your pipeline will also be outputting the test function as a member variable for the output class. In this case the output might look something like:
function Test() {
this.test = function() { console.log('test'); };
}
This means that whenever you write new Test() the test function is going to be recreated every single time.
Output as class prototype function
In the other major possibility, your pipeline could be recognizing this as a function property and escape it from the class instance to the prototype. In this case the output might look something like:
function Test() {
}
Test.prototype = {
test: function() { console.log('test'); }
}
This means that no matter how many times you call new Test() there will still be only one creation of the test function around in memory.
Desired behavior
Hopefully it's clear that you want your end result to have the function end up on the prototype object rather than being recreated on each class instance.
However, while you would want the function to not end up as a property, that doesn't necessarily mean you couldn't write it that way in your own code. As long as your build chain is making the correct transformations, you can write it any way you prefer.
Although, looking at the default babel settings (which your babeljs tag leads me to believe you are using) it does not make this transformation for you. You can see this in action here. On the left I've created one class with the function as a property and one class with the function as a class method. On the right hand side, where babel shows it's output, you can see that the class with the function as a property still has it being an instance-level property, meaning it will be recreated each time that class's constructor is called.
I did find this babel plugin, which seems like it might add this transformation in, but I've not used it for myself so I'm not positive.
In my experience, the most reason for writing a method as a class property is when the method will be passed as a callback, and you need it to always be bound to the instance. React lifecycle methods will always be called as a method, so there's no reason to bind them (and you incur a tiny memory penalty when you do). Where this makes a difference is when you're passing a function to a component as a callback (e.g. onClick or onChange).
Take this example:
class BrokenFoo extends React.Component {
handleClick() {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
The function represented by this.handleClick is not automatically bound to the component instance, so when the method tries to read the value of this.props it will throw a TypeError because this is not defined. Read this article if you're not familiar with this; the problem described in section 4.2 "Pitfall: extracting methods improperly" is essentially what's happening when you pass around a method without making sure it's bound correctly.
Here's the class, rewritten with the handler as a class property:
class HappyFoo extends React.Component {
handleClick = () => {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
Effectively, you can think of the handleClick definition in the second example as placing this code into the component's constructor (which is just about exactly the way Babel does it):
this.handleClick = () => {
alert(this.props.message);
}
This achieves the same thing as calling bind on the function (as described in the linked article) but does it a little differently. Because this function is defined in the constructor, the value of this in this.props.message is bound to the containing instance. What this means is that the function is now independent of the calling context; you can pass it around and it won't break.
The rule of thumb that I follow: by default, write methods as methods. This attaches the method to the prototype and will usually behave the way you'd expect. However, if the method is ever written without parentheses (i.e. you're passing the value and not calling it), then you likely want to make it a class property.

Write global functions to use in all components in angular

Note : Its not for global variable but for a global common function to perform a functionality on all components
I am working on an angular app where I have around 400 components in different modules, almost all components have one same kind of functionality as mentioned below
There is a sections on many pages which shows a "How to work section" which can be closed by users and will remain closed unless they open it again, I have done it with cookies which I set on click on close or open icon but this function is written in a component and this needs to be imported in other components
I want to create a functions somewhere which perform this functionality on click on icon and can be called without importing any component in others.
One way to do it ( as I thought ) could be create a JavaScript function in a file and load it in index file and then call this function on click on close and open icon
Not sure if this is the best way to do this. Hope someone will come up with a better solution.
1. create your global function service, i.e. 'funcs.services.ts' under 'services' directory:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class FuncsService {
constructor() { }
myGlobalAddFunction(a){
return a++;
}
mySecondFunc(){
// add more... and so on
}
}
2. Import the function in your component:
// your path may different
import { FuncsService } from './../services/funcs/funcs.service';
//...
constructor(
private funcs: FuncsService
) {}
ngOnInit(): void {
let x = 1;
myResult = this.funcs.myGlobalAddFunction(x);
// Then you are expecting 2 for return value
}
3. Hope that works... :)
You can export a function that is a written in .ts file and then call it in all your components.
export function myFunction(){
// Do something
}
And then import the function myFunction() in other components. That works fine for me and can be useful in certain cases
This isn't the best solution (in my opinion). The best solution would be to either create a service, or an utils class.
But if you want to do this, I suggest you make a JS file, that you declare in your angular-cli.json file under the scripts property, containing your functions.
EDIT Now that you've came back to reason, here is a code sample to make utils classes.
export const IMG_UTILS = {
convertPngToJpg = (picture: any) => {
// Your logic here
}
};
export const VIEW_MANAGER = {
isAdblockActive = () => {
// test if an ad-blocker is active
}
};
You can make any utils class you want in a const, then put it into a file. Then, you can put this file in an utils folder, and request it with
import { VIEW_MANAGER } from 'src/app/utils/view-manager';
Otherwise, you can make a service, which is handled by Angular, with a console command such as
ng g s services/view-manager/view-manager
And it will behave the exact same way : you will import it in your components to use it.
Hope this helps !
The most recommended way is to use a service and inject it whenever needed, but there is a way to have a function available globally.
Although I don't think it's a really good idea, you can add the function in the index.html file, then whenever you want to use it, you have to use #ts-ignore to avoid an error from being thrown.
e.g
index.html
<script>
function globalFunc(){
alert(2)
}
</script>
anywhere else on the app
// #ts-ignore
globalFunc();
List item
Just to chime in with possibly a duplicate answer albeit more fleshed out... I have a utilities class which I use.
For example:
export class Utilities {
// Simple promise wrapper for setTimeout. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#creating_a_promise_around_an_old_callback_api
public static Wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
}
The class is referenced in a component via the import statement:
import { Utilities } from 'path/to/Utilities';
And then you can call your static methods thus:
Utilities.Wait(30000)
.then(() => DoStuff())
.catch(() => console.log('Darn!'));
I would tend to use RxJs but I've written it this way to keep things a little cleaner.

What is the proper way to export a NON-singleton class in NodeJS?

I recently learned that all node modules are cached and behave similar to singletons in most instances.
The problem I am trying to solve is to not have every import result in the same instance being returned. This is probably very simple to figure out however I'm having trouble landing on a solid design pattern as I'm new to Node and ES6.
The goals I'm trying to achieve are:
Private fields
Consumers of the imported module can new up instances
instanceof comparison
The best I was able to come up with is the following:
export default () => {
let _foo = 'bar';
return new class {
get foo() {
return _foo;
}
set foo(value) {
_foo = value;
}
};
};
However this doesn't quite meet all the goals I'm trying to achieve.
Using this method importing modules can't use instanceof to compare prototypes.
It also doesn't matter if importers use the new keyword when creating an instance. Calling let instance = new Module() and let instance = Module() result in the same thing.
I tried to get around this by removing the new keyword from the functions return however this resulted in the importer having to do the following to get a new instance: new (Module())
I have also tried exporting constructor functions but this resulted in the loss of private fields.
What is the proper way to export a constructor function/class from a node module?
UPDATE:
After playing around some more I was able to come up with the following:
const _sFoo = Symbol();
export default class {
constructor() {
this[_sFoo] = 'default';
}
get foo() {
return this[_sFoo];
}
set foo(value) {
this[_sFoo] = value;
}
}
This seems to meet all of my goals however I'm still not sure if this is the best design pattern...
The problem I am trying to solve is to not have every import result in the same instance being returned. This is probably very simple to figure out however I'm having trouble landing on a solid design pattern as I'm new to Node and ES6.
You have a couple options:
You can export the constructor and let the code that is loading your module call that constructor to create their own object. This allows the calling code to create as many independent objects as they desired. Exporting a constructor would require new to be used by the caller unless the constructor explicitly detects they were called without new and then adapts to still return a new instance.
You can export a factory function and let the code that is loading your module call that factory function to create as many of their own objects as they want. The factory function would be just called as a normal function and it would return a new object each time it was called.
You can export a method that, when called, does whatever you want including creating the desired object and returning it (perhaps embedded in an object of other things too). This is just a variant of the factory function, but may include a bunch of things at once.
The goals I'm trying to achieve are:
Private fields
The above do not help you at all with private fields per object. That is a completely separate discussion.
Consumers of the imported module can new up instances
Option 1 above allows the caller to use new directly. The other options are factory functions so they would not use new.
instanceof comparison
You have to export the constructor directly (option 1 above) in order to use instanceof with it. The other options don't export the constructor so you don't have anything to use instanceof with.
What is the proper way to export a constructor function/class from a node module?
You just export the constructor. In Javascript, constructors are just functions so you just export the constructor and then the caller can use let x = new SomeConstructor() to create their own object. They can likewise use if (x instanceof SomeConstructor). With ES6 syntax, you just export the class name and that's equivalent to exporting the constructor.

Categories

Resources