Export javascript object to be used as new instance - javascript

So I have my menu.js file and inside I have a Menu object as shown below:
let Menu = {
elt: null,
settings: {
title: '',
}
}
export { Menu };
Now, I'm wanting to use the menu object to build another menu in another file, as shown here:
const test = new Menu('', {
// Empty
});
For some reason, it's not letting me use the export, I'm also tried export default Menu; with no luck, it keeps coming back with the following error:
Does anyone know the proper way to instantiate an object literal?

In ES6 (AKA ES2015), JavaScript introduced classes. These work just like classes in other programming languages (if you know any), with a constructor, methods, and getters and setters (all are optional). You might want to consider switching to the following code:
menu.js:
class Menu {
constructor() {
this.elt = null;
this.settings = {
title: ""
}
}
// Other methods
}
export { Menu }
main.js:
import { Menu } from "menu";
const test = new Menu();
However, if you want to put parameters, you can change the Menu constructor to:
constructor(elt = null, settings = {
title: ""
}) {
this.elt = elt;
this.settings = settings;
}
Then, in main.js,
import { Menu } from "menu";
const test = new Menu("", {
// Empty
});

Related

JavaScript function call context has valid parameters, but function doesn't get them

In a custom event-handling setup using callbacks, the calling context of the callback shows valid values for the callback parameters, but the argument values are undefined after stepping into the function.
In case it matters, this is inside of an Electron renderer process which uses React.
In a vanilla JavaScript object, the debugger shows expected contextual values for everything on the line of the callback reporting SerialPortEvent.Opened.
// file: serialPort.js (no imports)
class SerialPortEvent {
Discovered = 0
Opened = 1
Closed = 2
DataReceived = 3
Error = 4
}
class SerialPortSpec {
...
addEventListener(listener) {
this.listeners.push(listener)
}
open(baudRate) {
const baudRateInt = parseInt(baudRate, 10)
window.serialport.open(this.portInfo.path, baudRateInt)
.then(binding => {
this.baudRate = baudRateInt
this.binding = binding
// Here, the debugger shows all locals are as expected
this.listeners.forEach(listener => listener(SerialPortEvent.Opened))
}).catch(reason => {
this.listeners.forEach(listener => listener(SerialPortEvent.Error, reason))
})
}
...
}
...
module.exports = { SerialPortEventHub, SerialPortSpec, SerialPortEvent }
However, one "step into" later, at the beginning of the callback function "portEventHandler", the argument values are undefined. I would love to know why! Thanks.
// file SerialPortUI.jsx
import React from 'react'
import { SerialPortEventHub, SerialPortEvent, SerialPortSpec } from './serialPort'
import './serialportui.css'
class SerialPortPanel extends React.Component {
...
portEventHandler(eventType, ...data) {
// Here, eventType is undefined. This file does import SerialPortEvent.
switch (eventType) {
...
}
}
...
}
class SerialPortEvent {
Discovered = 0
Opened = 1
Closed = 2
DataReceived = 3
Error = 4
}
That's not a proper enum declaration. Class fields will be created on an instance, the static class property SerialPortEvent.Opened you are accessing in your code is indeed undefined. And that's the value the called function receives.
Instead, you'll want to use an object with properties:
const SerialPortEvent = {
Discovered: 0,
Opened: 1,
Closed: 2,
DataReceived: 3,
Error: 4,
};
Never use class syntax if you don't ever instantiate it (use new)!

Circular reference using dependency inversion issue

I have a circular reference issue using this pattern approach. TypeError: Class extends value undefined is not a constructor or null .
The strange thing is, if I move the field.type.ts in src/constants.ts, it doesn't throw an error and it works as expected, but crashes on the Unit Tests. If it leave the fied.type.ts contents in it's own file, it crashes.
Maybe I am not using/understanding this dependency inversion pattern the right way. I could probably fixed by passing the FieldTypeToClassMapping as a parameter in Field.create(options: FieldOptions, fieldTypeMapping: FieldTypeToClassMapping), but I want to understand why this is happening.
import { StringField } from './string.field.model';
import { IntegerField } from './integer.field.model';
...
export const FieldTypeToClassMapping = {
//Constructor of eg. StringField class so I can use `new FieldTypeToClassMapping[options.type](options)`;
[FieldTypeEnum.STRING]: StringField,
[FieldTypeEnum.INTEGER]: IntegerField,
};
//field/field.ts
import { FieldOptions } from 'src/interfaces/field.options.interface';
import { FieldTypeToClassMapping } from 'src/model/template/field.type.to.mapping.ts'
export abstract class Field {
value: any;
type: string;
errors: string[] = [];
public constructor(options: FieldOptions) {
this.value = options.value;
this.type = options.type;
}
public static create(options: FieldOptions): any {
try {
return new FieldTypeToClassMapping[options.type](options);
} catch (e) {
throw new Error(`Invalid field type: ${options.type}`);
}
}
}
//field/integer.field.ts
import { FieldOptions } from 'src/interfaces/field.options.interface';
import { Field } from './field.model';
export class IntegerField extends Field {
constructor(options: FieldOptions) {
super(options);
}
protected validateValueDataType() {
this.validateDataType(this.value, "value");
}
protected validateDefaultDataType() {
this.validateDataType(this.defaultValue, "defaultValue");
}
}
//field/service.ts
payload const postFields = [
{
type: "string", //FieldTypeEnum.STRING,
value: 'a name'
},
];
const postFields = [
{
type: "string",
value: "John",
},
{
type: "integer",
value: 32,
},
];
const fieldsArray = [];
postFields.forEach((item) => {
const field: Field = Field.create(item);
fieldsArray.addField(field);
});
return fieldsArray;
The create(options: FieldOptions) function is defined inside the class Field, but then it tries to instantiate an instance of a class that extends Field.
I think that is where the problem arises. I don't know the entire contents of your files, but I imagine that at the top of any field.type.ts file you import Field. However since Field can instantiate any concrete implementation of itself it would need to know about them so you would need to import everything that extends Field inside Field.
I don't know/understand the dependency inversion pattern well enough to relate it to your question. But given the provided information, perhaps a Factory Pattern is what you need?
You could move the the function create(options: FieldOptions) to a FieldFactory class. Your create function is practically a factory function already.

Understanding VS Code IntelliSense/force VS Code IntelliSense

I'm working on a Node.js module in which several classes have to be exported. To save time, I decided to make export with a cycle. This is a snippet:
const _erros = {
MyError1: {
// fields
},
MyError2: {
// fields
}
// other errors
}
class BaseError extends Error {
constructor (data) {
// things
}
}
module.exports = Object.keys(_errors)
.reduce((acc, className) => Object.assign(acc, {
[className]: class extends BaseError {
constructor (message) {
const params = Object.assign({}, _errors[className])
params.message = message || params.message
super(params)
}
}
}), { BaseError })
Although the export is well done, VS Code IntelliSense detects only BaseError. Look at this image:
As you can see only BaseError is detected: MyError1, MyError2 and all other errors are not showed by IntelliSense.
Is this the proper VS Code behavior or it's a bug? And regardless the answer, is there a way to let VS Code IntelliSense work with exports made with cycles?

How to use use es6 classes in a VUE js app so that methods and data are bound to a class

I'm lookin for a better sulution to use ES6 classes in a VUE JS app.
I tried using es6 classes for my vue js app.
class App {
constructor(components) {
this.el = "#app";
this.data = {
dialog : new Dialog()
};
this.watch = {
"watcher": function (val) {
}
};
this.methods = {
get(){
console.log('get');
}
}
}
}
class Dialog {
constructor(components) {
this.title = "";
this.content = "";
}
}
var app = new Vue(new App());
Methods and data are not part of the class.
I am looking for a solution where it is posible to bind the data directly as properties and use the methods as you would do within a JS class.
class App {
constructor(components) {
this.dialog = new Dialog();
};
get(){
console.log('get');
}
}
Thanks in advance!

Can't Access Imported Classes in React Native

For some reason we're having a ton of trouble using classes/prototypes in react native... we're not sure if we're doing something wrong, if es6 isn't actually supported or what. How can we use classes in react native? Clearly we aren't doing something right.
What we've tried
Creating a function and adding prototypes to it and exporting at the bottom
Creating and exporting a class with a constructor
Importing with {} and without, and exporting with default
The errors
Db is not a constructor
_Db2.default is not a constructor
Cannot read property 'default' of undefined
_Db.Db is not a constructor
No matter what we've tried, we cannot import an object of our creation and instantiate it. Here is an example of the prototype we've set up in another stackoverflow post we made when trying to untangle the issue
Here is an example of how we're importing it in.
import Db from '../localstorage/db/Db';
//var Db = require('../localstorage/db/Db');
const db = new Db();
When using require, it seems like the import statement works and an attribute we assign in the constructor exists, but none of the other prototypes are in the object.
EDIT 1: Below is our class implementation. We are instantiating realm outside of the class because realm seems to crash when instantiated inside of a class as documented in this github issue.
const realm = new Realm({
schema: [Wallet, WalletAddress, WalletTransaction, Log, APIWallet, APITransaction, APIAccount, Configuration],
path: config.db_path
});
export default class Db extends Object {
constructor() {
super();
this.realm = realm;
logger(2, realm.path);
}
//https://realm.io/docs/javascript/latest/#to-many-relationships
doOneToMany(one, many) {
many.forEach(m => {
this.write(() => {
one.push(m);
});
});
}
query(model, filter) {
let results = this.realm.objects(model);
if (filter) {
return results.filtered(filter);
}
return results;
}
insert(model, options) {
if (options == undefined && model instanceof Realm.Object) {
this.write(() => {
realm.create(model);
});
} else {
this.write(() => {
realm.create(model, options);
});
}
}
update(obj, options) {
this.write(() => {
Object.keys(options).map((key, attribute) => {
obj[key] = attribute;
});
});
}
del(model, obj) {
this.write(() => {
realm.delete(obj);
});
}
write(func) {
try {
realm.write(func);
} catch (e) {
logger(0, e);
throw new Error('Db.js :: Write operation failed ::', e);
}
}
close() {
Realm.close();
}
}
//module.exports = { Db };
The answer was we had a circular dependency in a Logger.js file that required Db.js while Db.js required Logger for useful logging. Removing the circular dependency caused classes and all the other import issues to go away.

Categories