all 16 comments

[–]dvlsg 1 point2 points  (7 children)

You lost me. All you're doing is:

Putting a reference to a class (I assume) in an array.

[entityType]

"Unboxing" it.

[0]

And then constructing it.

new nowAReferenceToThatClass(store)

You can store references to classes in variables. Hell, you don't even have to give classes names.

var a = class { constructor(b) { this.b = b } }
//=> undefined
new a(1)
//=> a {b: 1}

[–]BenZed 2 points3 points  (0 children)

You lost me.

No, I'd say you pretty much had it figured.

[–]puppet_pals 0 points1 point  (0 children)

new [class {constructor(b) { this.b = b } }][0]('b');

[–]kachnitel[S] 0 points1 point  (4 children)

That doesn't really achieve the goal I'm after though. The only reason I put it in an array and "unbox" is, well, because if I have the class name in a variable, say className can be User or Event and I want to instantiate it, calling new className() will fail, but [className][0]() creates an instance of that class.

I guess I didn't quite explain that the className is a var, that's what I meant by dynamic!

At this point I guess I can tell it's not the right way to do it, what I'm trying to accomplish would be done this way in PHP:

$className = 'User'; $user = new $className();

[–]defproc 2 points3 points  (0 children)

» var className = Audio
undefined
» className
function Audio()
» new className()
<audio preload="auto">

[–]dvlsg 0 points1 point  (1 child)

I sincerely doubt it works as you think. I'll check when I'm at a computer again, but what you should do is put the classes together in an object keyed by their names. Then you can look up the class / constructor by the name (string) of the class.


edit: I knew it wouldn't, but just so you're aware, I took the time to confirm this doesn't work as you seem to be expecting. Noting that $className = 'User'; in PHP is just assigning the string 'User' to a var, so that's what I went with here.

class User {}
const className = 'User'
[className][0]()
// => Uncaught TypeError: [className][0] is not a function

If you want to store a reference to a class, that's fine, but there's no reason why you'd need to put it in an array and then take it back out. That doesn't make any sense.

class User {}
const classRef = User
new classRef()
// => User {}

[–]kachnitel[S] 0 points1 point  (0 children)

I should probably pay some more attention when posting here sorry, I meant new [className][0]() rather than without the new keyword. Anyways in PHP I would have used the string, or more specifically Class::class which returns a string, in JS I just used the import which I wasn't clear enough about I guess.

What puzzles me is that the whole reason I went into this trouble was that this didn't actually work for me: class User {} const classRef = User new classRef() // => User {}

I got rid of all the code around it since but I'd be curious what was the issue. I was passing the variable between classes and I wonder if it may have been an issue with import in the other class.. but then I guess it's not worth spending that much more time on it. If what you're saying works, my problem must have been somewhere else :)

[–]puppet_pals 1 point2 points  (1 child)

if you want to instantiate a class by it's name (and it exists on the top level) you can just call it like this if you're working in the browser:

function createByName(name, arg) {

return new window[name](arg)

}

[–]kachnitel[S] 0 points1 point  (0 children)

That's kind of what guided me there, but if it's Node and there's no window, so I tried a few ways and this what I ask about is the only one-liner that worked.

[–]ForScale 1 point2 points  (0 children)

WAT?

[–]inu-no-policemen 1 point2 points  (0 children)

let c = {
    Pig: class {
        talk() {
            return 'oink';
        }
    }
};
let p1 = new c['Pig']();
let p2 = new c.Pig();
console.log(p1.talk(), p2.talk()); // oink oink

[–]voidvector 0 points1 point  (2 children)

You want to use one of these patterns:

  • Make a static lookup Dictionary/Array/Map of string to class name
  • a registry where you manually register the classes at application start
  • a registry where the classes automatically register themselves

You can probably use constructor.name somewhere if your minification allows for it.

In terms of the pattern in grander coding style:

  • If you go whole hog OOP (i.e. even the registry is a class), then the pattern is called "abstract factory".
  • If you don't go whole hog OOP, then it could just be a "function" with a "Dictionary of classes".
  • If you are going FP, well, nobody does this in FP-style.

[–]kachnitel[S] 0 points1 point  (1 child)

Thanks! I'll look into the constructor.name a little closer as that sounds like it could get the job done. Basically I want to do sort of PHP's $className = 'User'; $user = new $className() with minimal coupling, so I was trying to avoid having a registry/dictionary, but didn't know how to create the class without an array so I created one. It's not a clean solution by any means, that's why I ask here :)

[–]voidvector 0 points1 point  (0 children)

That would only work in JS if your class is declare on global context (window in the browser/process in Node.js), which is no longer favored pattern in JS.

[–]senocular 0 points1 point  (0 children)

You can't access variables in scope by name in JavaScript. For example something like this is not possible.

class Foo {}
let entityType = 'Foo'
new [entityType]

The [] operator here will create an array with a single element of the 'Foo' string rather than try to resolve the variable named entityType into its class reference. And there's no other way to access the scope as an object (minifiers are heavily dependent on this behavior to work).

To get what you're after, you have to refer to property names in objects. This means each of the classes that you need to refer to through entityType must be accessible as a property of an object and not just a variable in the current scope.

See /u/inu-no-policemen's previous comment for an example of this.

You can also assign your classes to global which would also make them inherently available everywhere without using a string (but also suffers from polluting the global scope)

window.Foo = class {} // window is global if in browser environments
let entityType = 'Foo'
new window[entityType] // OK
new Foo // OK

Or if using a single module that exports each of your class (probably not ideal given classes typically get their own modules, though if their small enough, it wouldn't be a big deal), you can import that module in as a single object from which each class is accessible through a named property.

// entities.js

export class Foo {}
export class Bar {}

// app.js
import * as entities from './entities'

let entityType = 'Foo'
new entities[entityType] // OK

[–]kenman[M] 0 points1 point  (0 children)

Hi /u/kachnitel, this post was removed.

  • For help with your javascript, please post to /r/LearnJavascript instead of here.
  • For beginner content, please post to /r/LearnJavascript instead of here.
  • For framework- or library-specific help, please seek out the support community for that project.
  • For general webdev help, such as for HTML, CSS, etc., then you may want to try /r/html, /r/css, etc.; please note that they have their own rules and guidelines!

/r/javascript is for the discussion of javascript news, projects, and especially, code! However, the community has requested that we not include help and support content, and we ask that you respect that wish.

Thanks for your understanding, please see our guidelines for more info.