繁体   English   中英

JavaScript:如何在不使用 new 关键字的情况下创建类的新实例?

[英]JavaScript: How to create a new instance of a class without using the new keyword?

我认为以下代码将使问题变得清晰。

// 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);

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

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

这不行吗?

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

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

如果实在不想用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;
};

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

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;
}

因为 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 中的 Object.create 函数中借用的一个:Douglas Crockford 的 The Good Parts

//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 关于包括 Object.create 在内的新 ES5 特性的文章)。

在 ES5 中,你可以这样做:

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

我希望有帮助

其它的办法:

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

您还可以做的是使用eval

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM