【问题标题】:JavaScript: How to create a new instance of a class without using the new keyword?JavaScript:如何在不使用 new 关键字的情况下创建类的新实例?
【发布时间】:2010-12-07 13:00:09
【问题描述】:

我认为下面的代码会让问题更清楚。

// My class
var Class = function() { console.log("Constructor"); };
Class.prototype = { method: function() { console.log("Method");} }

// Creating an instance with new
var object1 = new Class();
object1.method();
console.log("New returned", object1);

// How to write a factory which can't use the new keyword?
function factory(clazz) {
    // Assume this function can't see "Class", but only sees its parameter "clazz".
    return clazz.call(); // Calls the constructor, but no new object is created
    return clazz.new();  // Doesn't work because there is new() method
};

var object2 = factory(Class);
object2.method();
console.log("Factory returned", object2);

【问题讨论】:

  • 为什么不能使用new关键字?
  • 丹尼尔,事实上你可以,我错误地认为在这种情况下我不能。周五下午的疲劳,我猜 ;)。
  • J-P,以便其他人在必要时可以澄清问题。
  • 有史以来最奇怪的“尚未解决”和社区问题。
  • 我已经创建了一个装饰器来处理这个问题,请在这里查看我的答案:stackoverflow.com/a/44061744/427622

标签: javascript oop constructor instance


【解决方案1】:

您还可以使用eval

当然,eval 存在安全问题,但它与任何其他动态实例化真的不同吗?

await import("/path/to/module") //use this to dynamically load module if you like
let obj = `eval new ${classname}();`

【讨论】:

    【解决方案2】:

    这不行吗?

    function factory(class_, ...arg) {
        return new class_(...arg);
    }
    

    我不明白你为什么不能使用new

    【讨论】:

    • 规定没有使用“新”
    • 该死的!这很好用。我认为(错误地!)在这种情况下我不能使用“new”关键字,但是当然,如​​果 new 采用刚刚定义的“类”,或者是否传递了该“类”并不重要函数的参数,稍后调用“新”。我笨。
    • 对我不起作用。我在 FF22 上得到的只是“TypeError:class_ 不是构造函数”
    • 好的热门,您如何将参数列表应用于这个新创建的类? ;) new class_().apply(this,array) 我不这么认为
    • @Lpc_dark 一针见血!也许你可以做function factory(class_, ...args) {return new class_(...args)}
    【解决方案3】:

    另一种方式:

    var factory = function(clazz /*, arguments*/) {
        var args = [].slice.call(arguments, 1);
        return new function() { 
            clazz.apply(this, args)
        }
    }
    

    【讨论】:

      【解决方案4】:

      没有“工厂”的更简单、更清洁的方式

      function Person(name) {
        if (!(this instanceof Person)) return new Person(name);
        this.name = name;
      }
      
      var p1 = new Person('Fred');
      var p2 = Person('Barney');
      
      p1 instanceof Person  //=> true
      p2 instanceof Person  //=> true
      

      【讨论】:

        【解决方案5】:

        因为 JavaScript 没有类,让我改写你的问题:如何在不使用 new 关键字的情况下基于现有对象创建新对象?

        这是一个不使用“new”的方法。它不是严格意义上的“新实例”,但它是我能想到的唯一不使用“新”(并且不使用任何 ECMAScript 5 功能)的方法。

        //a very basic version that doesn't use 'new'
        function factory(clazz) {
            var o = {};
            for (var prop in clazz) {
                o[prop] = clazz[prop];
            }
            return o;
        };
        
        //test
        var clazz = { prop1: "hello clazz" };
        var testObj1 = factory(clazz);
        console.log(testObj1.prop1);    //"hello clazz" 
        

        您可能会喜欢并设置原型,但随后您会遇到跨浏览器问题,我试图保持简单。此外,您可能希望使用“hasOwnProperty”来过滤您添加到新对象的属性。

        还有其他使用“新”的方式,但有点隐藏它。这是从JavaScript: The Good Parts by Douglas Crockford 中的 Object.create 函数借用的一个:

        //Another version the does use 'new' but in a limited sense
        function factory(clazz) {
            var F = function() {};
            F.prototype = clazz;
            return new F();
        };
        
        //Test
        var orig = { prop1: "hello orig" };
        var testObj2 = factory(orig);
        console.log(testObj2.prop1);  //"hello orig"
        

        EcmaScript 5 有 Object.create 方法,它会做得更好,但仅在较新的浏览器(例如 IE9、FF4)中受支持,但您可以使用 polyfill(填补裂缝的东西),例如作为ES5 Shim,以获得旧浏览器的实现。 (见John Resig's article on new ES5 features including Object.create)。

        在 ES5 中你可以这样做:

        //using Object.create - doesn't use "new"
        var baseObj = { prop1: "hello base" };
        var testObj3 = Object.create(baseObj);
        console.log(testObj3.prop1);
        

        希望对你有帮助

        【讨论】:

          【解决方案6】:

          我猜独立于浏览器的解决方案会更好

          function empty() {}
          
          function factory(clazz /*, some more arguments for constructor */) {
              empty.prototype = clazz.prototype;
              var obj = new empty();
              clazz.apply(obj, Array.prototype.slice.call(arguments, 1));
              return obj;
          }
          

          【讨论】:

          • Dima,为什么这个比 Dave 提出的方案更独立于浏览器?
          • 因为 "obj.__proto__ = something" 不适用于所有浏览器,并且 Dave 的解决方案不支持构造函数的参数
          【解决方案7】:

          如果您真的不想使用new 关键字,并且不介意只支持Firefox,您可以自己设置原型。不过,这没有任何意义,因为您可以使用 Dave Hinton 的答案。

          // This is essentially what the new keyword does
          function factory(clazz) {
              var obj = {};
              obj.__proto__ = clazz.prototype;
              var result = clazz.call(obj);
              return (typeof result !== 'undefined') ? result : obj;
          };
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-07-15
            • 1970-01-01
            • 2021-07-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多