Modules vs Class memory difference - javascript

I have some methods and properties that I would like to be available to other files in my JS application.
I see I have 2 options, I can either have a class:
class MusicTile {
artistTitle = find('someProperty')
play() {
// Some logic
}
}
And then do let myTile = new MusicTiles
Or just export like so
let artistTitle = find('someProperty')
function play() {
// Some logic
}
export { play }
And just import { * } from './musicTile.js'
I'm curious which of the 2 is better to use. I don't really need to instantiate MusicTile, I just want the properties from there so I guess a plain old export is fine. But is there something else to consider?
Also how is memory usage between the two, I guess the export doesn't do anything unless I call the methods in there. But the class approach (at least how it is with the artistTitle = find('someProperty') outside a method) would call find() as soon as I do new MusicTile so consume more memory?

Related

Js using reflection to create subclass in parentclass method

I got this idea about js extends system. It'll be much easier to understand what i mean by reading the following codes
in moduleA.js I have Frame class
class Frame{ // contains frame info
static Predefined_Paramters_Pattern = [1,2,3,4]
constructor(someParameters = {variable1=...,variable2=...,tag = 0}){
//do something
this.someParamtersPattern = someParamters
}
nextFrame(){
// for example
// when i call nextFrame it 'll construct 4 subclasses
// base on [this] constructor paramaters
// constructorParmatersPattern = {variable1=...,variable2=...,tag= 1 or 2 or 3 or 4}
// this code may looks meaningless
// but i just wanna make this a lot easier to be comprehended what i mean
// and avoid stucking into a complex business logic
Frame.Predefined_Paramters_Pattern.forEach(e=>{
// create sub class somehow
let type = this.type
this.someParamtersPattern.tag = e
let constructorParmatersPattern = this.someParamtersPattern
// if i use eval(`new ${type}(${constructorParmatersPattern })`)
// the browser will throw a error looks like 'SubFrame1 is not define'
})
}
}
export {Frame}
in moduleB.js I have SubFrame1 class
import {Frame} from './moduleA.js'
class SubFrame1 extends Frame{
constructor(somePramaters){
//do something
super(somePramaters)
//do something
this.type = 'SubFrame1'
}
}
export {SubFrame1}
Now what I want to achieve is when i call new SubFrame1().nextFrame(), it'll create several SubFrames automaticlly which are similar to the one I created. I can define some patterns for their constructor's paramaters. So no matter how many subclasses i have, as long as they extends Frame, then they all share the same patterns when they call .nextFrame().
But the thing is I do not wish to have a SubFrame1 class or SubFrame1,SubFrame2,...,SubFrame3 classes 's reference in my original class.
like this one
import {SubFrame1} from './subframe1.js'
import {SubFrame2} from './subframe2.js'
......
import {SubFrameN} from './subframen.js'
class Frame{
......
}
i'm pretty much a rookie to javascript but at school i was tought and told to write codes so I can reuse them and reduce redundant codes, any help or corrections would be great
So you want new SubFrame1().nextFrame() to construct a SubFrame1 instance, but new SubFrame2().nextFrame() to construct a SubFrame2 instance. Nothing easier than that, you don't even need a type property for that! JS prototype object (e.g. built with class syntax) already do contain a .constructor property holding the constructor function that you can call to create a new instance of the same (sub)class.
export class Frame{ // contains frame info
constructor(someParameters) {
// do something
this.someProperties = someParameters;
}
nextFrame() {
const type = this.constructor;
const instance = new type(this.someProperties);
return instance;
}
}
Now this assumes that the subclass constructors would be called with the same signature, and always expect the this.someProperties object as arguments for the cloning of the frame. To customise this, the subclass could of course modify this.someProperties, but as soon as the signatures become too different the subclass should better override the whole method:
class SpecialFrame extends Frame {
constructor(someParameters, someSpecials) {
super(someParameters);
this.specialProperties = someSpecials;
}
nextFrame() {
return new this.constructor(this.someProperties, this.specialProperties);
}
}
This can also be used for more complex initialisation than just copying a property value, or for hardcoding some specific arguments that nextFrame should always use. If nextFrame does more than just the cloning, split it into two methods - clone() that creates the copy and may be overridden in the subclasses, and nextFrame that calls this.clone() then modifies the copy to become the next frame instead of the same.
Edit : Bergi offered a much better solution!
____________________________________________________________________
I find out how i do this with es6 Reflect API in this link below
Create instance of "Class" Using "Reflection" in JavaScript
posted by soulshined
in moduleA.js
class Frame{ // contains frame info
static Predefined_Paramters_Pattern = [1,2,3,4]
constructor(someParameters = {variable1=...,variable2=...,tag = 0}){
//do something
this.someParamtersPattern = someParamters
}
nextFrame(){
Frame.Predefined_Paramters_Pattern.forEach(e=>{
// create sub class
let type = this.type
this.someParamtersPattern.tag = e
let constructorParmatersPattern = this.someParamtersPattern
Reflect.construct(this.type, constructorParmatersPattern )
})
}
}
export {Frame}
and subclass
import {Frame} from './moduleA.js'
class SubFrame1 extends Frame{
constructor(somePramaters){
//do something
super(somePramaters)
//do something
this.type = SubFrame1
}
}
export {SubFrame1}

Import ES6 dependency inside class constructor

I have a JS/ES6 class with a constructor that needs to dynamically load a dependency based on the settings passed to it.
It works perfectly with CommonJS syntax:
class Example {
handler = null;
constructor(dependency) {
try {
this.handler = new (require(dependency))();
} catch {
throw new Error(`${dependency} not installed`);
}
}
/* ... */
}
However, I haven't been able to get it to work properly in ES6 module format. Here's as far as I've been able to get to:
class Example {
handler = null;
constructor(dependency) {
try {
this.handler = new (await import(dependency)).default();
} catch {
throw new Error(`${dependency} not installed`);
}
}
/* ... */
}
This doesn't work because you cannot use await without async, and a class constructor cannot be async.
Without await, further code tends to fail, as there is no guarantee the dependency has been loaded in time.
I cannot load the dependency outside of the class in the ordinary way, because it can be essentially any arbitrary dependency the consumer of the class defines.
I would prefer not to have a separate init/build method that the consumer needs to worry about. Ideally, you should be able to just do const ex = new Example('some-dependency') and then have instant access to the methods of the class in ex, without any need for further boilerplate on the consumer side.
The constructor could of course call a static build method, but that seems to just be moving the asynchronous problem to a different location.
Is there an established pattern or a kludgey hack to achieve this in ES6 modules?

Using TypeScript Generics with Feature Checks [duplicate]

This question already has an answer here:
Is it possible to use the generic type to determine runtime functionality?
(1 answer)
Closed 2 years ago.
I am working with new and legacy pieces of UI and for a new feature that is rolling out, am using a feature toggle to decide which piece of the UI to show. The back-end, for the new feature now returns a different model so, throughout my code base, I have to account for this by creating V2 versions of existing methods/properties.
Throughout my code, there is a lot of this:
let someCollection: ModelV1 | ModelV2;
this.featureEnabled
? someCollection = someCollection as ModelV2
: someCollection = someCollection as ModelV1;
With the usage of TypeScript, I would like to create a generic function that would return to me whichever type I ask for and would abstract the feature check.
Another example is when I use the feature check to set a specific version of a property to a specific version of an array:
if (this.featureEnabled) {
this.someCollectionV2 = this.usersV2.filter(user => user.selected);
} else {
this.someCollection = this.users.filter(user => user.selected);
}
It's cumbersome to have this spread out over my code and it feels like a code-smell. How can I optimize this and make it more functional?
The OOP way to handle this would be to define an interface which has all of the functionality that depends on whether the feature is enabled. Then your main class stores an instance of a feature class which is either enabled or disabled. The main class only needs to check in one place -- where it creates and stores the feature instance -- and after that it never needs to check again because both classes have the same interface.
In my opinion this is the way to go as it resolves all of the typescript issues and also removes lots of if statements and unnecessary branching. We don't even need to store the featureEnabled boolean because we don't need it. Here's a dummy setup:
interface DependentFunctions {
doSomething(): number;
}
class MyClass {
private _handler: DependentFunctions;
constructor(featureEnabled: boolean) {
if ( featureEnabled ) {
this._handler = new V2Class();
} else {
this._handler = new V1Class();
}
}
exampleMethod() {
const num = this._handler.doSomething();
}
}
class V2Class implements DependentFunctions {
doSomething() {
return 2;
}
}
class V1Class implements DependentFunctions {
doSomething() {
return 1;
}
}
Playground Link
If you want to instead tackles typescript issues directly, then you can make use of type guards and assertion functions.
Some Examples

require exported typescript class in javascript

I'm moving my nodejs project from Javascript to Typescript. It's going to be a slow process, slowly changing things over a few months as i need to tweak stuff.
I've created a typescript class that looks something like this:
// RedisRepository.ts
export class RedisRepository {
public async getDevice(serial: string) : Promise<Device> {
// blah
return device;
}
}
Then in another Javascript file where i need to reference and then call the functions on the above class.
// ExpressApi.js
const repository = require('../Redis/RedisRepository');
async function getRedis(req, res) {
try {
const device = await repository.getDevice('serialnumberxxx');
res.status(200).end(JSON.stringify(device ));
} catch (e) {
logger.error(e);
res.status(500).end();
}
}
however, when it tried to call the function on the repository it says it doesn't exist. Using chrome debugger, i can see that it exists at: repository.RedisRepository.prototype.getDevice. This doesn't seem the correct way to use the function though.
While I appreciate I could just convert ExpressApi.js to Typescript. I'm going to have this problem with many different files. So i need to use it as JavaScript for now. I'll slowly continue to go round the project and change things to Typescript.
As #crashmstr mentioned, you should create a new instance of RedisRepository, then call getDevice method.
If you still want to use
const repository = require('../Redis/RedisRepository');
syntax, you could export default new RedisRepository() from your RedisRepository.ts file.

Mixing object construction with application logic

I've started refactoring my code to make it testable. One area I've found a problem is where I've mixed object construction with application logic. If I have a constructor called SomeClass which performs application logic but also instantiates another class I run in to problems when I try to test:
function SomeClass() {
//does lots of application type work
//but then also instantiates a different object
new AnotherClass();
}
Testing becomes difficult because now I need to find a way to create AnotherClass in the test environment.
I've dealt with this problem using dependency injection. So SomeClass takes an instance of AnotherClass as a parameter:
function SomeClass(anotherObj) {
}
Problem with this is as far as I can see is all this does is defer the problem to somewhere else in my application. I still have to create the anotherObj from AnotherClass somewhere else in my code.
This google testing article http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html suggests:
In order to have a testable code-base your application should have two
kinds of classes. The factories, these are full of the "new" operators
and are responsible for building the object graph of your application,
but don't do anything.And the application logic classes which are devoid of the "new" operator and are responsible for doing work.
This sounds exactly like my problem and the factory type pattern is what I need. So I tried something like:
function anotherClassFactory() {
return new AnotherClass();
}
function SomeClass() {
anotherClassFactory();
}
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
(I'm making this a community wiki answer because I frankly think it only answers part of the question, while leaving too much unsaid. Hopefully others with more knowledge can improve it.)
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
According to this article linked by the one you linked, you do it like this:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass(a) {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
a.foo();
// ...app logic...
}
someclass-test.js:
function someClass_testSomething() {
var sc = new SomeClass({
foo: function() { /* ...appropriate `foo` code for this test... */}
});
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
app.js:
function buildApp() {
return {
// ...lots of various things, including:
sc: new SomeClass(new AnotherClass())
};
}
So the real app is built using buildApp, which gives SomeClass its AnotherClass instance. Your tests for SomeClass would use someClass_testSomething and such, which uses the real SomeClass but a mocked-up instance rather than a real AnotherClass containing just enough of it for the purposes of the test.
My dependency-injection-fu is weak, though, and I frankly don't see how buildApp scales to the real world, nor do I see what you're supposed to do if a method has to create an object to do its job, e.g.:
SomeClass.prototype.doSomething = function() {
// Here, I need an instance of AnotherClass; maybe I even need to
// create a variable number of them, depending on logic internal
// to the method.
};
You're not going to pass everything the method needs as arguments, it would be a spaghetti nightmare. This is probably why for more static languages, there are usually tools rather than just coding patterns involved.
In JavaScript, of course, we have another option: Just go ahead and use new AnotherClass in the code:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass() {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
(new AnotherClass()).foo();
// ...app logic...
}
someclass-test.js:
var AnotherClass;
function someClass_testSomething() {
// Just enough AnotherClass for this specific test; there might be others
// for other tests
AnotherClass = function() {
};
AnotherClass.prototype.foo = function() { /* ...appropriate `foo` code for this test... */};
var sc = new SomeClass();
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
You use anotherclass.js and someclass.js in your real app, and you use someclass.js and someclass-test.js when testing SomeClass.
That's a rough sketch, of course; I'm assuming your real-world app probably doesn't have globals (SomeClass, AnotherClass) all over the place, but however it is you're containing SomeClass and AnotherClass can presumably also be used to contain SomeClass, and to contain the tests for it and their various fake AnotherClasss.

Categories

Resources