【问题标题】:How do I make JavaScript Object using a variable String to define the class name?如何使用变量字符串创建 JavaScript 对象来定义类名?
【发布时间】:2010-11-24 20:47:36
【问题描述】:

这就是我想要做的——这是伪代码,不起作用。有谁知道如何真正做到这一点:

// Define the class
MyClass = Class.extend({});

// Store the class name in a string
var classNameString = 'MyClass';

// Instantiate the object using the class name string
var myObject = new classNameString();

【问题讨论】:

    标签: javascript oop


    【解决方案1】:

    如果你做这样的事情会起作用吗:

    var myObject = window[classNameString];
    

    ..?

    【讨论】:

    • 认为你的意思是window[classNameString](没有引号)。只要MyClass 移动到较低(即function)范围,就会中断。 @kirk:是的,这是跨浏览器。
    • 如何使用这种方法将参数传递给构造函数?
    • @JamesMcMahon 在这种情况下,您必须使用window[classNameString](args)。但正如 Crescent Fresh 提到的,要小心,因为这在某些情况下可能会中断。
    • 这似乎对我不起作用。经过反复试验,我发现这可行:var obj = new Home(id);,但后来却不行:var obj = new window["Home"](id);。我试图让它工作:new window[x](id); where x = "Home"... 我得到的错误是Uncaught TypeError: window[x] is not a constructor
    • 警告:这个won't work for ES6 classes
    【解决方案2】:

    如果 MyClass 是全局的,您可以使用下标表示法将其作为窗口对象的属性进行访问(假设您的代码在浏览器中运行)。

    var myObject = new window["MyClass"]();
    

    【讨论】:

    • 这适用于所有浏览器吗?我看到一些帖子抱怨它对他们不起作用。
    【解决方案3】:

    顺便说一句:window 是浏览器 JavaScript 中对全局对象的引用。这也是this,即使在 Node.js、Chrome 扩展、转译代码等非浏览器环境中也应该可以工作。

    var obj = new this[classNameString]();

    限制是被调用的类必须在全局上下文中。如果您想将其应用于范围类,您需要这样做:

    var obj = (Function('return new ' + classNameString))()

    但是,确实没有理由使用字符串。 JavaScript 函数本身就是对象,就像字符串也是对象一样。

    编辑

    这是获得在严格模式和非浏览器 JS 环境下工作的全局范围的更好方法:

    var global;
    try {
      global = Function('return this')() || (42, eval)('this');
    } catch(e) {
      global = window;
    }
    
    // and then
    var obj = new global[classNameString]
    

    发件人:How to get the global object in JavaScript?

    【讨论】:

    • 如果从全局上下文中调用,它只是thiswindow 无论您身处何种环境都可以工作,所以我认为没有理由更喜欢 this 而不是 window
    • 如答案所述,您所处的环境不一定是浏览器。因此,最好使用this,因为在非浏览器环境中window 可能是未定义的,或者不是您所期望的。
    • @XedinUnknown 通常,当您编写一段 javascript 时,您会知道它是用于客户端还是用于节点。如果您知道它是针对浏览器的,那么更喜欢 window 而不是 this 没有任何缺点。
    • @Sebi,问题中没有任何地方暗示环境是客户端。此外,客户端也不一定意味着“浏览器”。答案提供了一种通过明确引用全局上下文来满足 OP 要求的方法——这就是重点。我指出从全局上下文引用全局上下文的唯一可靠方法是this,而不是window。此外,不从全局上下文引用全局上下文的最可靠方法是top。另外,将其注入闭包中可能会很好。
    • @devios1 如果您测试代码,您会注意到它可以在任何上下文中工作,而不仅仅是全局上下文。这就是我们使用Function('return this')() 而不是return this 的原因。前者自动切换到全局上下文。无论上下文如何,这都有效。窗口可以被覆盖,并且只是浏览器。最好不知道代码执行上下文来编写跨平台代码。我给出的答案是跨平台且不能被覆盖,因此比使用window 好得多。它可以在转译的代码中工作,如 webpack、gulp 和节点、扩展等。请先测试它。
    【解决方案4】:

    这是一个更强大的解决方案,可以与命名空间函数一起使用:

    var stringToFunction = function(str) {
      var arr = str.split(".");
    
      var fn = (window || this);
      for (var i = 0, len = arr.length; i < len; i++) {
        fn = fn[arr[i]];
      }
    
      if (typeof fn !== "function") {
        throw new Error("function not found");
      }
    
      return  fn;
    };
    

    例子:

    my = {};
    my.namespaced = {};
    (my.namespaced.MyClass = function() {
      console.log("constructed");
    }).prototype = {
      do: function() {
        console.log("doing");
      }
    };
    
    var MyClass = stringToFunction("my.namespaced.MyClass");
    var instance = new MyClass();
    instance.do();
    

    【讨论】:

    • 为什么(windows || this),不是总是要定义窗口吗?
    • @JamesMcMahon:我们所知道的世界不再是现实。像nodejs这样的租户也来占领我们的星球了! :)
    • 由于出现了严格模式(ECMA-262 ed 5,2009 年),如果 thiswindow || this 可能会在非浏览器环境中返回 undefined不是由调用设置的(在示例中没有)。
    • 您好如何使用它并使其适用于导入的类?例如从'../../mazes/components/Grid'导入网格
    【解决方案5】:

    这里是 Yuriy 方法的改进版本,它也可以处理对象。

    var stringToObject = function(str, type) {
        type = type || "object";  // can pass "function"
        var arr = str.split(".");
    
        var fn = (window || this);
        for (var i = 0, len = arr.length; i < len; i++) {
            fn = fn[arr[i]];
        }
        if (typeof fn !== type) {
            throw new Error(type +" not found: " + str);
        }
    
        return  fn;
    };
    

    【讨论】:

      【解决方案6】:

      如果classNameString 来自安全来源,您可以使用

      var classNameString = 'MyClass';
      var myObject = eval("new " + classNameString + "()");
      

      此解决方案适用于命名空间,并且独立于平台(浏览器/服务器)。

      【讨论】:

      • 不知道也不知道为什么被删?
      • @Jacksonkr,这是否也意味着我一开始就不应该喝啤酒,因为这可能会成为一个坏习惯? :)
      • 根据您的类比:当您听说这是一个坏主意时使用eval 就像酒后驾车一样。 “什么都没发生……呃……上次我开车喝酒……呃……事实上我喝醉了更好!……呃……” 等出了问题,已经太晚了。不要成为那个人。
      • 提倡永远不要使用函数,无论是eval还是其他,都是不好的建议。如果它是一个没有任何用例的功能,那么它现在已经被贬低并作为一项功能被删除了。
      • 正是 MacroMan。将其作为答案删除是荒谬的。
      【解决方案7】:
      function myClass(arg){
      }
      
      var str="myClass";
      dynamic_class=eval(str);
      
      var instance=new dynamic_class(arg); // OK
      

      编辑:内联示例

      function Person(name){
          this.name=name;
      }
      var person1=new (eval("Person"))("joe");
      

      【讨论】:

        【解决方案8】:

        在 Firefox 上,扩展有安全规则,Javascript 控制台也是如此。不要犯我在控制台中测试的错误,因为这些解决方案都不起作用。 而当您从页面进行测试时,效果会更好:

        • eval 解决方案效果很好
        • Function('return new '... 有效(对象已创建),但构造函数的参数作为“未定义”传递 我没有测试其他解决方案。

        法语: Sur Firefox il y a des règles de sécurité qui s'appliquent aux extensions, et donc à la console Javascript。 Ne faites pas l'erreur que j'ai faite de tester depuis la console car aucune de ces solutions ne marchent。 对 teste depuis une page cela fonctionne mieux 的反对意见:

        • la solution eval fonctionne bien
        • Function('return new '... fonctionne (l'objet est créé) sauf que les paramètres du constructor sont "undefined" Je n'ai pas testé les autres 解决方案。

        【讨论】:

          【解决方案9】:

          浏览器全局对象是window,每当您使用var 定义全局变量或使用function 定义函数时,您就是在window 中添加它们。 因此你可以在那里得到你的“类”定义:

          var args = [];
          var className = 'MyClass';
          var obj = new window[className](args);
          

          但这不适用于 ES6 类声明

          使用 ES6 关键字 class 声明的类按标准处理不同。

          class MyClass { } 声明的类定义了一个不会成为window 全局对象的属性的全局类。换句话说,以下适用

          class MyClass {};
          typeof window.MyClass === 'undefined';
          

          那么,如何对 ES6 类做同样的事情呢?对象访问表示法是必需的,因为它需要解析字符串名称,但要搜索的父对象不再可用。

          一种方法是创建您自己的上下文对象,在那里声明您的类并在那里搜索它。在代码中:

          // this variable actually goes in `window`
          var classes = {};
          // declare class inside
          classes.MyClass = class {
             // the class code
          };
          
          var args = [];
          var className = 'MyClass';
          var obj = new classes[className](args); // dynamic for "new classes.MyClass(args)"
          

          【讨论】:

            猜你喜欢
            • 2018-09-07
            • 1970-01-01
            • 1970-01-01
            • 2012-05-27
            • 2011-06-23
            • 1970-01-01
            • 2013-04-12
            相关资源
            最近更新 更多