I defined a class in a module:
"use strict";
var AspectTypeModule = function() {};
module.exports = AspectTypeModule;
var AspectType = class AspectType {
// ...
};
module.export.AspectType = AspectType;
But I get the following error message:
TypeError: Cannot set property 'AspectType' of undefined
at Object.<anonymous> (...\AspectType.js:30:26)
at Module._compile (module.js:434:26)
....
How should I export this class and use it in another module? I have seen other SO questions, but I get other error messages when I try to implement their solutions.
// person.js
'use strict';
module.exports = class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
display() {
console.log(this.firstName + " " + this.lastName);
}
}
// index.js
'use strict';
var Person = require('./person.js');
var someone = new Person("First name", "Last name");
someone.display();
If you are using ES6 in Node 4, you cannot use ES6 module syntax without a transpiler, but CommonJS modules (Node's standard modules) work the same.
module.export.AspectType
should be
module.exports.AspectType
hence the error message "Cannot set property 'AspectType' of undefined" because module.export === undefined.
Also, for
var AspectType = class AspectType {
// ...
};
can you just write
class AspectType {
// ...
}
and get essentially the same behavior.
With ECMAScript 2015 you can export and import multiple classes like this
class Person
{
constructor()
{
this.type = "Person";
}
}
class Animal{
constructor()
{
this.type = "Animal";
}
}
module.exports = {
Person,
Animal
};
then where you use them:
const { Animal, Person } = require("classes");
const animal = new Animal();
const person = new Person();
In case of name collisions, or you prefer other names you can rename them like this:
const { Animal : OtherAnimal, Person : OtherPerson} = require("./classes");
const animal = new OtherAnimal();
const person = new OtherPerson();
Use
// aspect-type.js
class AspectType {
}
export default AspectType;
Then to import it
// some-other-file.js
import AspectType from './aspect-type';
Read http://babeljs.io/docs/learn-es2015/#modules for more details
I simply write it this way
in the AspectType file:
class AspectType {
//blah blah
}
module.exports = AspectType;
and import it like this:
const AspectType = require('./AspectType');
var aspectType = new AspectType();
class expression can be used for simplicity.
// Foo.js
'use strict';
// export default class Foo {}
module.exports = class Foo {}
-
// main.js
'use strict';
const Foo = require('./Foo.js');
let Bar = new class extends Foo {
constructor() {
super();
this.name = 'bar';
}
}
console.log(Bar.name);
Several of the other answers come close, but honestly, I think you're better off going with the cleanest, simplest syntax. The OP requested a means of exporting a class in ES6 / ES2015. I don't think you can get much cleaner than this:
'use strict';
export default class ClassName {
constructor () {
}
}
I had the same problem.
What i found was i called my recieving object the same name as the class name. example:
const AspectType = new AspectType();
this screwed things up that way...
hope this helps
Sometimes I need to declare multiple classes in one file, or I want to export base classes and keep their names exported because of my JetBrains editor understands that better. I just use
global.MyClass = class MyClass { ... };
And somewhere else:
require('baseclasses.js');
class MySubclass extends MyClass() { ... }
Related
Is it possible to modify customElements.define and use a custom function instead?
This is what I have tried so far, but obviously this does not work because window.customElements is read only.
const future = ["hello-world"];
let customElementsRegistry = window.customElements;
const registry = {};
registry.define = function(name, constructor, options) {
if (future.includes(name)) {
customElementsRegistry.define(name, constructor, options);
}
}
window.customElements = registry;
window.customElements.define("hello-world", HelloWorld);
Is this possible or is my only option to create my own registry and just use that one?
The property is still configurable so you can redefine it. Though this doesn't look like a great idea for production app.
const future = ["hello-world"];
let customElementsRegistry = window.customElements;
const registry = {};
registry.define = function(name, constructor, options) {
console.log('hijacked')
if (future.includes(name)) {
customElementsRegistry.define(name, constructor, options);
}
}
Object.defineProperty(window, "customElements", {
get() {
return registry
}
})
window.customElements.define("hello-world", class HelloWorld extends HTMLElement {
constructor() {
super()
this.innerHTML = "Hello World"
}
});
<hello-world>Test</hello-world>
Class Life {
constructor(name = 'no name') {
this.name = name;
}
getName() {
return this.name;
}
setName(name = 'no name') {
this.name = name;
}
}
const MyLife = new Life();
export { getName, setName } = MyLife;
export default MyLife;
How can I use the same instance of new Life() i.e, MyLife throughout my code?
Things I have tried;
const MyLife = new Life();
export const getName = MyLife.getName.bind(MyLife);
export const setName = MyLife.setName.bind(MyLife);
export default MyLife;
Every time I try to use this in another file i.e, myOther.js
import { setName } from '../path-of-class.js`
setName('Luke Skywalker'); // I get undefined.
What am I doing wrong here?
P.S: the class is in another library, I compile it with webpack & then use in another <package>, The class above works fine if used locally within the same <package> but when I try to use from <package-a> to <package-b> I get setName of undefined.
Try saving your instance of Life into a static variable probably near the class and return it with a static method
class Life {
static getInstance() {
if (!Life.instance) {
Life.instance = new Life();
}
return Life.instance;
}
constructor(name = 'no name') {
this.name = name;
}
getName() {
return this.name;
}
setName(name = 'no name') {
this.name = name;
}
}
Life.instance = null;
export default Life;
in another file:
import Life from 'module';
const myLife = Life.getInstance();
I'm not completely certain how webpack handles the imports. But having a single instance of a class and using it everywhere is a common pattern in object oriented programming (lookup singleton), usually solved by attaching a static variable of the instance to a class and getting it with a static method. This example achieves the same thing by having a static instance and using getInstance() to return it or create one if it wasn't already. This is a classic implementation of this pattern.
I have created the following two classes in my classes.js:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
display() {
console.log(this.firstName + " " + this.lastName);
}
}
module.exports = {
Person
};
As you can see I am exporting the two classes via module.exports.
Person = require('./classes.js');
const someone1 = new Person("First name", "Last name"); // <-- does NOT work
const someone = new Person.Person("First name", "Last name"); // does work
someone.display();
However, when calling the classes I get an error, when calling the class directly.
Any suggestions how to call the class directly?
I appreciate your replies!
If you want all your classes in one file called classes.js, then this should work;
// classes.js
class Person {
// ...
}
class Vehicle {
// ...
}
module.exports = {
Person,
Vehicle
}
// some-other-file.js
const { Person } = require('../classes')
const person = new Person('First', 'Last')
Although to keep things easy to understand, my recommendation would be to split your class into multiple files and then export each class from its file directly;
class Person {
// ...
}
module.exports = Person
const Person = require('../classes/person')
// do something
In this case you're exporting an object containing Person class
module.exports = {
Person
};
So when you import like Person = require('./classes.js')
You're actually importing the exported object. So Person after you've imported is similar to
Person = {
Person
};
You can either change the export by assigning the desired export object to module.exports like:
module.exports = Person
or change your import to use destructuring assignment to import like (notice the curly braces):
const { Person } = require('./classes.js');
If
module.exports = {
Person
};
therefore
Person = require('./classes.js').Person;
Alternatively, you can
module.exports = Person;
and
Person = require('./classes.js');
In classes.js you are exporting Person as an object property. So to make it work as you expect you can either do Destructuring Assignment
const { Person } = require('./classes')
Or just require class directly from classes.js file.
const Person = require('./classes').Person
Alternatively, and it's a better option, in my opinion, you can separate Person to its own file and export it by default.
File ./Person.js
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
display() {
console.log(this.firstName + " " + this.lastName);
}
}
module.exports = Person
And then in your main file just do:
const Person = require('./Person');
I have a Node.js v11.11.0 app. In this app, my files are structured like the following:
./src
/animals/
animal.js
tiger.js
koala.js
index.js
As shown above, I have three classes defined in the animals directory. Over time, I intend to add additional animals with more complex logic. At this time, my classes are defined like so:
animal.js
'use strict';
class Animal {
constructor(properties) {
properties = properties || {};
this.kind = 'Unknown';
}
eat(foods) {
for (let i=0; i<foods.length; i++) {
console.log(`Eating ${foods[i]}`);
}
}
}
module.exports = Animal;
tiger.js
'use strict';
const Animal = require('./animal');
class Tiger extends Animal {
constructor(properties) {
super(properties);
this.kind = 'Tiger';
}
eat(foods) {
for (let i=0; i<foods.length; i++) {
if (foods[i].kind === 'meat') {
console.log(`Eating ${foods[i]}`);
}
}
}
}
module.exports = Tiger;
koala.js
'use strict';
const Animal = require('./animal');
class Koala extends Animal {
constructor(properties) {
super(properties);
this.kind = 'Koala';
}
eat(foods) {
for (let i=0; i<foods.length; i++) {
if (foods[i].kind === 'plant') {
console.log(`Eating ${foods[i]}`);
}
}
}
}
module.exports = Koala;
I am trying to dynamically create an instance of one of these classes based on what the user enters. For example, I'm doing this:
index.js
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
})
readline.question('What animal file do you want to load?', (fname) => {
let properties = {
name: 'My Pet'
};
let Animal = require(fname);
let pet = Object.create(Animal.prototype, properties);
});
If I run this and enter ./animals/tiger.js, I get an error. The error says: Property description must be an object. I don't understand this. Both Tiger and Koala extend Animal. At the same time, as my list will be dynamic, I need the free form option of typing a file path and dynamically loading the class. For that reason, I can't use the approach shown here, which specifically lists the Class names.
How do I dynamically load a class and create an instance of that class with specific properties?
The second argument to Object.create is the same argument you would pass to Object.defineProperties, your properties is therefore invalid. Instead use Object.assign:
Object.assign(Object.create(Animal.prototype), properties)
But why don't you just call the constructor?
new Animal(properties)
Secondly this:
properties = properties || {};
is probably intended to be:
this.properties = properties || {};
And I wouldn't recommend to dynamically require, especially not from a user entered value, instead create a lookup object:
const AnimalByName = {
Bear: require("./Bear"),
//...
};
const instance = new AnimalByName[name](properties);
I have a basic migration class that looks like this:
"use strict";
var Schema = require('../database/schema');
var sequence = require('when/sequence');
var _ = require('lodash');
class Migrate {
constructor(knex) {
this.knex = knex;
}
createTable(tableName) {
...
}
createTables() {
...
}
run() {
return this.createTables();
}
}
module.exports = (knex) => {
return new Migrate(knex)
}
and I can use it like so:
require('./app/commands/' + process.argv[2] + '.js')(knex)
.run()
.then((...))
However, I want to inherit from an abstract class called "Command", so I add the following lines to my "Migrate" class.
"use strict";
var Command = require('./command');
class Migrate extends Command {
...
}
The problem is, I don't know how I can convert my Command class to a module. Right now it is like this:
"use strict";
module.exports = class Command {
sayHello() {
console.log("hello");
}
}
but it doesn't work. (e.g this becomes undefined on Migrate class' constructor method so I cannot put Knex to the instance)
Is there any proper way to use abstract classes with module pattern?
Thank you.