2

Suppose I have the following JavaScript class code. (EDIT: the code is running as an ES6 module that is imported using the standard ES6 "import" statement. So the following class is in a standalone file "C.js")

export class C {
    static f() {
        console.log("hello world")
    }
}

Now I want to import the module and invoke the method C.f(), but I only have the name of the method as a string. The following works fine:

import {C} from "C.js"
var methodName="f"
C[methodName]()

Now suppose that I also have the name of the class as a string as follows:

import {C} from "C.js"
var className="C"
var methodName="f"
/* How do I invoke C.f() ? */

Things I've tried:

  • Using window/self/globalThis, which do NOT work:
import {C} from "C.js"
var className="C"
var methodName="f"
/* none of the below calls work */
window[className][methodName]()
self[className][methodName]()
globalThis[className][methodName]()

I've tried using the Function() constructor:

import {C} from "C.js"
var className="C"
var methodName="f"
/* the following does NOT work: */
var fn = new Function(className+"."+methodName+"()")
fn()

The above code gives an error that "C" is not defined, when the fn() is executed.

I've also tried using "eval()", which would be my last choice anyways since I don't really need to evaluate "arbitrary" code. I just want to execute a static method in a class, whose names are in strings.

import {C} from "C.js"
var className="C"
var methodName="f"
var code = className + "." + methodName + "()"
eval(code)

The above does NOT work in the Chrome web browser as part of a modern ES6 JavaScript application. The problem in the Chrome web browser is that the global "environment" used within "eval" does NOT see the "C" class definition.

So, what is the best way to implement this very simple call using string values for the class name and method name?

import {C} from "C.js"
var className="C"
var methodName="f"
/* now what? */
deltamind106
  • 638
  • 7
  • 19
  • Is the class defined in a module? Imported global variables aren't in `window`. – Barmar Feb 23 '22 at 19:20
  • Yes it is all in an ES6 module as part of a Vue.JS application – deltamind106 Feb 23 '22 at 19:20
  • 3
    Then there's no built-in way to access the name dynamically. Add all your classes to an object and use that. – Barmar Feb 23 '22 at 19:21
  • Wow if that's true then JavaScript is a joke. – deltamind106 Feb 23 '22 at 19:21
  • 2
    `myClasses = {"C": C}` then use `myClasses[className]` – Barmar Feb 23 '22 at 19:21
  • 4
    Variable variables are almost always the wrong solution for something. – Barmar Feb 23 '22 at 19:22
  • A lot of the time when a person needs to do this, they need a better solution. Sounds like you need something to register classes so you can use that to call your stuff dynamically. – epascarello Feb 23 '22 at 19:23
  • 1
    To be fair, the call to the JavaScript function call is originating from a Lua script, whose interpreter is running inside an Ionic capacitor plugin. This whole thing runs as part of a mobile app in Android. – deltamind106 Feb 23 '22 at 19:23
  • So no, there is no other "solution". My Lua code needs to invoke an arbitrary JavaScript function. It shouldn't be this hard to do this in a modern programming language. – deltamind106 Feb 23 '22 at 19:24
  • 1
    In `Class C`, `Class` should be all lowercase. I'm not sure how you're code worked. – code Feb 23 '22 at 19:26
  • 1
    It's a little ironic that you complain about a "modern programming language" when you're using Lua. – Pointy Feb 23 '22 at 19:26
  • 1
    `JavaScript is a joke` - eval is a joke, since its scope doesn't include your imported module's classes. But we already knew that. Also, python does the same, https://stackoverflow.com/questions/65186578/why-python-eval-can-access-imported-functions-but-not-classes – James Feb 23 '22 at 19:28
  • @Pointy Good job dragging the conversation way off topic, but Lua was not my choice of languages-- it was dictated by other parts of the project. JavaScript was not really my choice either, but at least that language sees a lot of modern attention, so I expected better. – deltamind106 Feb 23 '22 at 19:30
  • @code Ah another typing critic. Yes, I mistyped it into the stackoverflow editor. Sorry to completely derail your efforts to assist. – deltamind106 Feb 23 '22 at 19:31
  • JavaScript wasn't built to work with Lua, so there's no need for variable variable names. If you must, why don't you use an object? Again, your class declaration is invalid syntax. – code Feb 23 '22 at 19:31
  • 1
    The bottom line is that JavaScript was not designed to be a "slave" language to other software. I don't use the word "slave" in a negative way; I just mean that JavaScript was designed to be the primary programming environment, and not to be a system that could be controlled by another environment. There *are* environments that do that, like some Swift APIs from Apple, but that's a pretty specialized thing. Also, it would perhaps be helpful if you could describe the overall system you're working with; how exactly is your Lua code even attempting to connect with JavaScript? – Pointy Feb 23 '22 at 19:33
  • 1
    Seems like your code is something Lua specific. Your function constructor example works perfectly in my Chromium console: `new Function("C"+"."+"f"+"()")();` – code Feb 23 '22 at 19:35
  • @barmar can you please answer this question with you library object solution? This conversation is getting a bit out of hands – savageGoat Feb 23 '22 at 19:37
  • 1
    @deltamind106 to get back to the topic: you stated that the class is part of an ES6 module that is imported. When importing the module `import module from ".."`, wouldn't it be possible to just use `module[className][functionName]()` ? – nah0131 Feb 23 '22 at 19:42
  • `import "C.js"` doesn't really work. If the *C.js* module does not `export` the class somehow, and does not store it into a global variable, the class won't be available outside of the module scope at all. The code `C[methodName]()` that you claim "*works fine*" doesn't work at all. – Bergi Feb 27 '22 at 20:34

1 Answers1

1

Since the answer is buried in the comments to the question, I figured I should go ahead and post it here as an actual answer, so future viewers can easily find the answer.

The answer is: In JavaScript, it's not possible to invoke a method in a class that was loaded from an ES6 module, where the name of the class is in a string.

deltamind106
  • 638
  • 7
  • 19