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.
Related
I want to ask, as in react we have HOC (Higher order components) where we pass components that modify it and then return modified Component for use
can we do same in javaScript?
for Example
// index1.js
// this is file where i am importing all the folder modules and exporting them
export { methodA, methodB } from './xyzAB'
export { methodC, methodD } from './xyzCD'
i am importing this file in another folder like this
import * as allMethods from './modules'
// this allows me to use this syntax
allMethods.methodA()
allMethods.methodB()
this is working fine, but i am looking for this kind of wrapper
// index2.js
// this is another file somewhere else where i want to use index1.js exported methods
import * as allMethods from './modules/xyz'
import anotherMethod from './somewhere/xyz'
// here i want customize some of `allMethods` functions and export them as new object
//which contains modifed version of default `index1.js` methods
allMethods.methodA = allMethods.methodA( anotherMethod ) // this is example of modified as HO Method
export default allMethods
My Above example may seem confusing,
why i am looking for such solution, i have set of utilities which i am trying to make them as library and use them in multiple projects,
now some of utils are dependent on main project related things, so instead of giving my utilities hard coded reference to their dependencies,
i want to pass different dependencies for different methods through my higher order method or configuration file,
so that each new project pass its dependent utilities from their config or higher order wrapper file as example shown above
I hope i was able to clear my question,
Few things which i tried,
i tried importing all modules in file which i count as wrapper file
in that if i try to use any module that returns webpack error as undefined method, due to methods not loaded fully until few seconds, i tried setTimeOut, that works fine, but this is not valid way of managing thing,
then i tried some async way, i used dynamic import() which returns promise, i used async/await syntax, and also used .then syntax but couldn't extract data and save it as variable (i may be doing something wrong at this step but i was totally failed) but this was only available with in promise or async await scope,
there were also other steps tried,
i am hoping i could find some neater syntax like below
import * as F from '../../core/lib/functions'
import { getModel } from '../entities'
F.getKeys = F.getKeys( getModel )
export default F
any suggestion is welcome
I think what you're looking for is some sort of currying or factory-like pattern.
There is no such thing as higher order modules but since JavaScript support higher order functions that is what you should use.
Just as a reminder, a higher order component is any component that takes a component as a parameter and returns another component. Similarly (simplified) a higher order function is one that takes a function as a parameter and returns a new function. (in reality all React components are more or less functions so thus why we are able to have higher order components).
The key thing is that you need to call a higher order function, not just import it (since again, there is no such thing as a higher order module). But this ties well into your idea of dependency injection.
I think, what you want is something like this in your utilities:
function a(dependency1, arg1, arg2) {}
function b(dependency2, arg1, arg2) {}
function createUtils(dependency1, dependency2) {
return {
a: a.bind(null, dependency1),
b: b.bind(null, dependency2)
}
}
This allows you to customize per project what dependency 1 and 2 are and the details for how they work (with some common interface). With the binding you don't have to pass that dependency in with every call to a function.
Then in one of your projects you'd set them up something like this:
import { createUtils} from 'utils';
import { dependency1, dependency2 } from 'somewhere' ;
const { a, b } = createUtils(dependency1, dependency2)
export { a, b };
You're not really doing any higher order function stuff, like I said this is more like a factory/dependency injection thing. Though bind is a higher order function (it takes the function it's called in and returns a new function with some arguments bound).
You can put place in createUtils for general modifications through another parameter with options. Or you can export smaller "factories" for each method that you want to be able to modify.
With that in mind you might to only export the raw functions from utils and use bind in your module setup code to bind the dependencies. I think bind is what you are missing. As well as that you have to create new functions to export, rather than modifying the imported functions. That also means that your imports in the rest of your code will come only from within your own module, not from the utils module.
I'm developing a web application in VueJs, Typescript and WebPack and I'm a bit confused about how to manage/split groups of functions (utilities and services).
I saw in various project in GitHub that some functions are declared and exported directly from the file ex:
utilities.ts
export function Sum(a:number, b:number):number{
return a+b;
}
this can be used with an import:
import {Sum} from "./utilities.ts"
let result = Sum(5,6);
Another common solution is to declare a const class:
otherUtilities.ts
export const OtherUtilities = {
Sum(a:number, b:number) : number => {
return a+b;
},
Hello() : string => {
return "Hello";
}
}
and import as:
import {OtherUtilities} from "./otherUtilities.ts"
let result = OtherUtilities.Sum(5,6);
What are the differences?
In the past, there was the Name Conflict issue with JS but now with the export/import technique via Loaders, this issue should be outdated, right?
Thank you
This object:
export const OtherUtilities = {
Sum(a:number, b:number) : number => {
return a+b;
},
Hello() : string => {
return "Hello";
}
}
Contains two completely unrelated functions. They don't need to share a this context, don't know each other, and could perfectly be exported as two separated functions, even in two separate modules. They can belong to the same object, but there is no strong reason to do that.
On the other hand, if you export them as separate entities:
export function sum()...
export function hello()...
They are tree shakeable. If your application happens to only import Hello(), them Sum can be dropped from the bundle.
Now, with the second strategy, you're more likely to get naming collisions. You can prevent them using the as keyword:
import {Sum} from 'one';
import {Sum as myCustomSum} from 'two';
Apart from the tree shaking, I don't think there's much differences between one style or the other. You can export anything with ECMAScript modules, would it be functions, strings, numbers or any other kind of primitives, arrays or objects. It's pretty much up to you and the code conventions of your team.
Some libraries used to export independent functions belonging to a big utility object, but then changed the style and switched to independent named exports, precisely to enable tree shaking (and sometimes, just independent projects do that, like lodash-es).
using functions:
export function sum(a: number, b: number): number {
return a + b;
}
using method :
export class Math {
static sum(a: number, b: number): number {
return a + b;
}
}
I'd like to do inheritance in an es6 class without the extends keyword:
Typical approach:
class Foo extends Bar {
contructor() {
...
}
}
What I am looking for is to generate an object with the same signature but using this pattern:
class Foo {
contructor(Bar) {
// use Bar class somehow
...
}
}
Thanks
== EDITS ==
Context:
I build an extension (ami) for a JS library threejs.
It provides new objects that seamlessly work in threejs.
Problem:
threejs has an internal mechanism to generate unique ids for each object, that is critical for its proper behavior.
Current implementations rely on three to be exposed as a global variable, so anybody that creates an object must reference it to ensure the ids are actually unique.
// in ami
// ID of this object will be unique accros all classes
// that are based of global THREE.Mesh
class Foo extends THREE.Mesh {
contructor() {
...
}
}
Using global variable works fine but I want to get rid of the global namespace requirement.
If I do not reference the same base elements in ami and in my application, id can conflict.
// in ami
import {Mesh} from 'three';
class Foo extends Mesh {
contructor() {
...
}
}
// in my app
import {Foo} from 'ami';
imoport {Mesh} from 'three';
const foo = new Foo(); // it uses "Mesh" from ami as a base.
const mesh = new Mesh(); // it uses current "Mesh" as a base.
// IDs will conflict...
One solution that could work is that I provide a new argument in ami constructors, to provide the three reference:
// in ami
class Foo {
contructor(mesh) {
...
}
}
// in my app
imoport {Mesh} from 'three';
import {Foo} from 'ami';
const foo = new Foo(Mesh);
const mesh = new Mesh();
But I do not know how to implement this solution.
This answer addresses the question as originally posed and was good enough to help the OP refine the question and garner immediate upvotes. I'd appreciate it if you didn't downvote it merely because the goalposts have moved.
Assuming that you are not crazy and this is a learning exercise, the best way to learn how to implement this is to get Typescript, write a class using extends, compile it with ES5 as the target, and look at the generated JavaScript. Ensure your base class has methods, properties, static methods, static properties, and a constructor with mixed required and optional parameters. Then derive another class from it and override some methods and replace some. You'll see how it's done by people who got serious about it.
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.
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.