Użycie.apply() z operatorem 'new'. Czy to możliwe?

W JavaScript chcę utworzyć instancję obiektu (za pomocą operatora new), ale przekazać konstruktorowi dowolną liczbę argumentów. Czy to możliwe?

Chcę zrobić coś takiego (ale poniższy kod nie działa):

function Something(){
    // init stuff
}
function createSomething(){
    return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something

Odpowiedź

Z odpowiedzi tutaj, stało się jasne, że nie ma wbudowanego sposobu połączenia .apply() z new operatorem. Jednak ludzie zasugerowali wiele naprawdę interesujących rozwiązania problemu.

Moim preferowanym rozwiązaniem był Ten od Matthew Crumley (zmodyfikowałem go, aby przekazać arguments właściwość):

var createSomething = (function() {
    function F(args) {
        return Something.apply(this, args);
    }
    F.prototype = Something.prototype;

    return function() {
        return new F(arguments);
    }
})();
Author: Prisoner ZERO, 2009-10-22

30 answers

Z ECMAScript5 ' S Function.prototype.bind Wszystko jest całkiem czyste:

function newCall(Cls) {
    return new (Function.prototype.bind.apply(Cls, arguments));
    // or even
    // return new (Cls.bind.apply(Cls, arguments));
    // if you know that Cls.bind has not been overwritten
}

Może być stosowany w następujący sposób:

var s = newCall(Something, a, b, c);

Lub nawet bezpośrednio:

var s = new (Function.prototype.bind.call(Something, null, a, b, c));

var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
To i rozwiązanie eval-based są jedynymi, które zawsze działają, nawet ze specjalnymi konstruktorami, takimi jak Date: {25]}
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true

Edit

Trochę wyjaśnienia: Musimy uruchomić new na funkcji, która pobiera ograniczoną liczbę argumentów. Metoda bind pozwala nam robić to jak więc:

var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();

Parametr anything nie ma większego znaczenia, ponieważ słowo kluczowe new resetuje kontekst f. Jest to jednak wymagane ze względów składniowych. Teraz, dla wywołania bind: musimy przekazać zmienną liczbę argumentów, więc robi to sztuczkę:

var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();

Owińmy to w funkcję. Cls jest przekazywany jako argument 0, więc będzie to nasz anything.

function newCall(Cls /*, arg1, arg2, ... */) {
    var f = Cls.bind.apply(Cls, arguments);
    return new f();
}

W rzeczywistości zmienna tymczasowa f nie jest wcale potrzebna:

function newCall(Cls /*, arg1, arg2, ... */) {
    return new (Cls.bind.apply(Cls, arguments))();
}

Wreszcie, powinniśmy się upewnić tego naprawdę potrzebujemy. (Cls.bind mogły zostać nadpisane). Więc zastąp go przez Function.prototype.bind, a otrzymamy końcowy wynik jak powyżej.

 376
Author: user123444555621,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-30 03:17:07

Oto uogólnione rozwiązanie, które może wywołać dowolny konstruktor (z wyjątkiem natywnych konstruktorów, które zachowują się inaczej, gdy są wywoływane jako funkcje, takie jakString, Number, Date, itd.) z tablicą argumentów:

function construct(constructor, args) {
    function F() {
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}

Obiekt utworzony przez wywołanie construct(Class, [1, 2, 3]) będzie identyczny z obiektem utworzonym przez new Class(1, 2, 3).

Możesz również stworzyć bardziej konkretną wersję, więc nie musisz za każdym razem przechodzić przez konstruktor. Jest to również nieco bardziej wydajne, ponieważ nie trzeba tworzyć nowa instancja wewnętrznej funkcji za każdym razem, gdy ją wywołujesz.

var createSomething = (function() {
    function F(args) {
        return Something.apply(this, args);
    }
    F.prototype = Something.prototype;

    return function(args) {
        return new F(args);
    }
})();

Powodem utworzenia i wywołania zewnętrznej funkcji anonimowej jest to, aby funkcja F nie zanieczyszczała globalnej przestrzeni nazw. Czasami nazywa się to wzorem modułu.

[UPDATE]

Dla tych, którzy chcą użyć tego w maszynopisie, ponieważ TS wyświetla błąd, Jeśli F zwróci cokolwiek:

function construct(constructor, args) {
    function F() : void {
        constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}
 261
Author: Matthew Crumley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-28 17:24:50

Jeśli Twoje środowisko obsługuje Operator spreadu ECMA Script 2015(...), możesz po prostu użyć go w ten sposób

function Something() {
    // init stuff
}

function createSomething() {
    return new Something(...arguments);
}

Uwaga: Teraz, gdy specyfikacja skryptu ECMA 2015 została opublikowana, a większość silników JavaScript aktywnie ją wdraża, byłby to preferowany sposób.

Możesz sprawdzić obsługę operatora spreadu w kilku głównych środowiskach, tutaj .

 32
Author: thefourtheye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-13 09:38:51

Załóżmy, że masz konstruktor Items, który zasłania wszystkie argumenty, które w niego rzucasz:

function Items () {
    this.elems = [].slice.call(arguments);
}

Items.prototype.sum = function () {
    return this.elems.reduce(function (sum, x) { return sum + x }, 0);
};

Można utworzyć instancję z obiektem.create (), a następnie .apply() z tą instancją:

var items = Object.create(Items.prototype);
Items.apply(items, [ 1, 2, 3, 4 ]);

console.log(items.sum());

Który po uruchomieniu wyświetla 10 od 1 + 2 + 3 + 4 == 10:

$ node t.js
10
 27
Author: substack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 17:18:47

W ES6, Reflect.construct() jest całkiem wygodne:

Reflect.construct(F, args)
 20
Author: gfaceless,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-21 09:00:54

@ Mateusz Myślę, że lepiej też naprawić własność konstruktora.

// Invoke new operator with arbitrary arguments
// Holy Grail pattern
function invoke(constructor, args) {
    var f;
    function F() {
        // constructor returns **this**
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    f = new F();
    f.constructor = constructor;
    return f;
}
 9
Author: wukong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 11:56:53

Możesz przenieść rzeczy init do osobnej metody Something ' s prototypu:

function Something() {
    // Do nothing
}

Something.prototype.init = function() {
    // Do init stuff
};

function createSomething() {
    var s = new Something();
    s.init.apply(s, arguments);
    return s;
}

var s = createSomething(a,b,c); // 's' is an instance of Something
 8
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-17 23:25:00

Ulepszona wersja odpowiedzi @ Mateusz. Ta forma ma niewielkie korzyści z wydajności uzyskane przez przechowywanie klasy temp w zamknięciu, a także elastyczność posiadania jednej funkcji, która może być użyta do utworzenia dowolnej klasy

var applyCtor = function(){
    var tempCtor = function() {};
    return function(ctor, args){
        tempCtor.prototype = ctor.prototype;
        var instance = new tempCtor();
        ctor.prototype.constructor.apply(instance,args);
        return instance;
    }
}();

To będzie używane przez wywołanie applyCtor(class, [arg1, arg2, argn]);

 8
Author: jordancpaul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-17 21:45:37

Ta odpowiedź jest trochę za późno, ale pomyślałem, że każdy, kto to widzi, może być w stanie z niej skorzystać. Istnieje sposób na zwrócenie nowego obiektu za pomocą apply. Chociaż wymaga to jednej małej zmiany w deklaracji obiektu.

function testNew() {
    if (!( this instanceof arguments.callee ))
        return arguments.callee.apply( new arguments.callee(), arguments );
    this.arg = Array.prototype.slice.call( arguments );
    return this;
}

testNew.prototype.addThem = function() {
    var newVal = 0,
        i = 0;
    for ( ; i < this.arg.length; i++ ) {
        newVal += this.arg[i];
    }
    return newVal;
}

testNew( 4, 8 ) === { arg : [ 4, 8 ] };
testNew( 1, 2, 3, 4, 5 ).addThem() === 15;

Aby pierwsza if wypowiedź zadziałała w testNew Musisz return this; u dołu funkcji. Jako przykład z Twoim kodem:

function Something() {
    // init stuff
    return this;
}
function createSomething() {
    return Something.apply( new Something(), arguments );
}
var s = createSomething( a, b, c );

Update: zmieniłem mój pierwszy przykład, aby zsumować dowolną liczbę argumentów, zamiast tylko dwóch.

 6
Author: Trevor Norris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-14 18:36:59

Właśnie natknąłem się na ten problem i rozwiązałem go w ten sposób:

function instantiate(ctor) {
    switch (arguments.length) {
        case 1: return new ctor();
        case 2: return new ctor(arguments[1]);
        case 3: return new ctor(arguments[1], arguments[2]);
        case 4: return new ctor(arguments[1], arguments[2], arguments[3]);
        //...
        default: throw new Error('instantiate: too many parameters');
    }
}

function Thing(a, b, c) {
    console.log(a);
    console.log(b);
    console.log(c);
}

var thing = instantiate(Thing, 'abc', 123, {x:5});
Tak, jest trochę brzydki, ale rozwiązuje problem i jest śmiertelnie prosty.
 6
Author: alekop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-25 20:09:21

Jeśli jesteś zainteresowany rozwiązaniem opartym na ewaluacji

function createSomething() {
    var q = [];
    for(var i = 0; i < arguments.length; i++)
        q.push("arguments[" + i + "]");
    return eval("new Something(" + q.join(",") + ")");
}
 4
Author: user187291,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-22 13:25:53

To działa!

var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);
 4
Author: infinito84,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 15:33:06

Zobacz też jak robi to CoffeeScript.

s = new Something([a,b,c]...)

Staje się:

var s;
s = (function(func, args, ctor) {
  ctor.prototype = func.prototype;
  var child = new ctor, result = func.apply(child, args);
  return Object(result) === result ? result : child;
})(Something, [a, b, c], function(){});
 3
Author: mbarkhau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-01 07:41:59

To podejście konstruktora działa zarówno ze słowem kluczowym new, jak i bez niego:

function Something(foo, bar){
  if (!(this instanceof Something)){
    var obj = Object.create(Something.prototype);
    return Something.apply(obj, arguments);
  }
  this.foo = foo;
  this.bar = bar;
  return this;
}

Zakłada wsparcie dla Object.create, ale zawsze możesz to zrobić, jeśli obsługujesz starsze przeglądarki. Zobacz tabelę wsparcia MDN tutaj .

Oto JSBin, aby zobaczyć go w akcji z wyjściem konsoli .

 2
Author: muffinresearch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-13 16:51:32

Roztwór Bez ES6 lub polyfills:

var obj = _new(Demo).apply(["X", "Y", "Z"]);


function _new(constr)
{
    function createNamedFunction(name)
    {
        return (new Function("return function " + name + "() { };"))();
    }

    var func = createNamedFunction(constr.name);
    func.prototype = constr.prototype;
    var self = new func();

    return { apply: function(args) {
        constr.apply(self, args);
        return self;
    } };
}

function Demo()
{
    for(var index in arguments)
    {
        this['arg' + (parseInt(index) + 1)] = arguments[index];
    }
}
Demo.prototype.tagged = true;


console.log(obj);
console.log(obj.tagged);


wyjście

Demo {arg1: "X", arg2: "Y", arg3: "Z"}


... lub "krótszy" sposób:

var func = new Function("return function " + Demo.name + "() { };")();
func.prototype = Demo.prototype;
var obj = new func();

Demo.apply(obj, ["X", "Y", "Z"]);


edit:
Myślę, że to może być dobre rozwiązanie:

this.forConstructor = function(constr)
{
    return { apply: function(args)
    {
        let name = constr.name.replace('-', '_');

        let func = (new Function('args', name + '_', " return function " + name + "() { " + name + "_.apply(this, args); }"))(args, constr);
        func.constructor = constr;
        func.prototype = constr.prototype;

        return new func(args);
    }};
}
 2
Author: Martin Wantke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-04 10:19:30

Nie można wywołać konstruktora ze zmienną liczbą argumentów, jak chcesz z operatorem new.

Możesz zmienić nieco konstruktor. Zamiast:

function Something() {
    // deal with the "arguments" array
}
var obj = new Something.apply(null, [0, 0]);  // doesn't work!

Zrób to zamiast:

function Something(args) {
    // shorter, but will substitute a default if args.x is 0, false, "" etc.
    this.x = args.x || SOME_DEFAULT_VALUE;

    // longer, but will only put in a default if args.x is not supplied
    this.x = (args.x !== undefined) ? args.x : SOME_DEFAULT_VALUE;
}
var obj = new Something({x: 0, y: 0});

Lub jeśli musisz użyć tablicy:

function Something(args) {
    var x = args[0];
    var y = args[1];
}
var obj = new Something([0, 0]);
 1
Author: Anthony Mills,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-22 21:31:23

Rozwiązania Matthew Crumleya w CoffeeScript:

construct = (constructor, args) ->
    F = -> constructor.apply this, args
    F.prototype = constructor.prototype
    new F

Lub

createSomething = (->
    F = (args) -> Something.apply this, args
    F.prototype = Something.prototype
    return -> new Something arguments
)()
 1
Author: Benjie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:38
function createSomething() {
    var args = Array.prototype.concat.apply([null], arguments);
    return new (Function.prototype.bind.apply(Something, args));
}

Jeśli twoja docelowa przeglądarka nie obsługuje ECMAScript 5 Function.prototype.bind, kod nie będzie działał. Nie jest to jednak zbyt prawdopodobne, patrz Tabela kompatybilności .

 1
Author: user2683246,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 01:23:55

Modified @ Mateusz odpowiedz Tutaj mogę przekazać dowolną ilość parametrów do działania jak zwykle (nie array). Również "coś" nie jest zakodowane na twardo:

function createObject( constr ) {   
  var args =  arguments;
  var wrapper =  function() {  
    return constr.apply( this, Array.prototype.slice.call(args, 1) );
  }

  wrapper.prototype =  constr.prototype;
  return  new wrapper();
}


function Something() {
    // init stuff
};

var obj1 =     createObject( Something, 1, 2, 3 );
var same =     new Something( 1, 2, 3 );
 1
Author: Eugen Konkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-04 14:22:47

Ten jednowarstwowy powinien to zrobić:

new (Function.prototype.bind.apply(Something, [null].concat(arguments)));
 1
Author: aleemb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-10 12:43:08

Podczas gdy inne podejścia są wykonalne, są zbyt złożone. W Clojure zazwyczaj tworzysz funkcję, która tworzy instancje typów / rekordów i używasz tej funkcji jako mechanizmu tworzenia instancji. Tłumaczenie tego na język JavaScript:

function Person(surname, name){
  this.surname = surname;
  this.name = name;
}

function person(surname, name){ 
  return new Person(surname, name);
}

Stosując takie podejście unikasz stosowania new z wyjątkiem przypadków opisanych powyżej. I ta funkcja, oczywiście, nie ma problemów z pracą z apply lub dowolną liczbą innych funkcji programowania funkcyjnego.

var doe  = _.partial(person, "Doe");
var john = doe("John");
var jane = doe("Jane");

Stosując takie podejście, wszystkie konstruktory typu (np. Person) są konstruktorami typu vanilla, do-nothing. Po prostu przekazujesz argumenty i przypisujesz je do właściwości o tej samej nazwie. Szczegółowe dane znajdują się w funkcji konstruktora (np. person).

Tworzenie tych dodatkowych funkcji konstruktora nie jest kłopotliwe, ponieważ są one dobrą praktyką. Mogą być wygodne, ponieważ pozwalają potencjalnie mieć kilka funkcji konstruktora o różnych niuansach.

 1
Author: Mario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-14 16:27:22

Ciekawe jest również, jak rozwiązano problem ponownego użycia tymczasowego konstruktora F() za pomocą arguments.callee, czyli samej funkcji creator/factory: http://www.dhtmlkitchen.com/?category=/JavaScript/&date=2008/05/11/&entry=Decorator-Factory-Aspect

 0
Author: polaretto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-20 16:08:42

Każda funkcja (nawet konstruktor) może przyjmować zmienną liczbę argumentów. Każda funkcja ma zmienną "arguments", która może być rzucona do tablicy z [].slice.call(arguments).

function Something(){
  this.options  = [].slice.call(arguments);

  this.toString = function (){
    return this.options.toString();
  };
}

var s = new Something(1, 2, 3, 4);
console.log( 's.options === "1,2,3,4":', (s.options == '1,2,3,4') );

var z = new Something(9, 10, 11);
console.log( 'z.options === "9,10,11":', (z.options == '9,10,11') );

Powyższe testy dają następujące wyniki:

s.options === "1,2,3,4": true
z.options === "9,10,11": true
 0
Author: Wil Moore III,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-18 17:10:46

Oto moja wersja createSomething:

function createSomething() {
    var obj = {};
    obj = Something.apply(obj, arguments) || obj;
    obj.__proto__ = Something.prototype; //Object.setPrototypeOf(obj, Something.prototype); 
    return o;
}

Na tej podstawie próbowałem symulować new słowo kluczowe JavaScript:

//JavaScript 'new' keyword simulation
function new2() {
    var obj = {}, args = Array.prototype.slice.call(arguments), fn = args.shift();
    obj = fn.apply(obj, args) || obj;
    Object.setPrototypeOf(obj, fn.prototype); //or: obj.__proto__ = fn.prototype;
    return obj;
}

Przetestowałem go i wydaje się, że działa doskonale we wszystkich scenariuszach. Działa również na natywnych konstruktorach, takich jak Date. Oto kilka testów:

//test
new2(Something);
new2(Something, 1, 2);

new2(Date);         //"Tue May 13 2014 01:01:09 GMT-0700" == new Date()
new2(Array);        //[]                                  == new Array()
new2(Array, 3);     //[undefined × 3]                     == new Array(3)
new2(Object);       //Object {}                           == new Object()
new2(Object, 2);    //Number {}                           == new Object(2)
new2(Object, "s");  //String {0: "s", length: 1}          == new Object("s")
new2(Object, true); //Boolean {}                          == new Object(true)
 0
Author: advncd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 07:11:18

Yes We can, javascript is more of prototype inheritance in nature.

function Actor(name, age){
  this.name = name;
  this.age = age;
}

Actor.prototype.name = "unknown";
Actor.prototype.age = "unknown";

Actor.prototype.getName = function() {
    return this.name;
};

Actor.prototype.getAge = function() {
    return this.age;
};

Kiedy tworzymy obiekt z "new", nasz utworzony obiekt dziedziczy getAge (), ale jeśli użyliśmy apply(...) or call(...) do wywołania aktora, to przekazujemy obiekt dla "this", ale obiekt, który przekazujemy WON'T dziedziczy z Actor.prototype

Chyba, że bezpośrednio zdamy aplikuj lub zadzwoń do aktora.prototyp, ale potem.... "to" wskazywałoby na " aktora.prototyp" i this.name napisz do: Actor.prototype.name. Wpływając tym samym na wszystkie inne obiekty utworzone z Actor...ponieważ nadpisujemy prototyp, a nie instancję

var rajini = new Actor('Rajinikanth', 31);
console.log(rajini);
console.log(rajini.getName());
console.log(rajini.getAge());

var kamal = new Actor('kamal', 18);
console.log(kamal);
console.log(kamal.getName());
console.log(kamal.getAge());

Spróbujmy apply

var vijay = Actor.apply(null, ["pandaram", 33]);
if (vijay === undefined) {
    console.log("Actor(....) didn't return anything 
           since we didn't call it with new");
}

var ajith = {};
Actor.apply(ajith, ['ajith', 25]);
console.log(ajith); //Object {name: "ajith", age: 25}
try {
    ajith.getName();
} catch (E) {
    console.log("Error since we didn't inherit ajith.prototype");
}
console.log(Actor.prototype.age); //Unknown
console.log(Actor.prototype.name); //Unknown

Przekazując Actor.prototype do Actor.call() jako pierwszy argument, gdy funkcja Actor() jest uruchomiona, wykonuje this.name=name, ponieważ "to" wskazuje na Actor.prototype, this.name=name; means Actor.prototype.name=name;

var simbhu = Actor.apply(Actor.prototype, ['simbhu', 28]);
if (simbhu === undefined) {
    console.log("Still undefined since the function didn't return anything.");
}
console.log(Actor.prototype.age); //simbhu
console.log(Actor.prototype.name); //28

var copy = Actor.prototype;
var dhanush = Actor.apply(copy, ["dhanush", 11]);
console.log(dhanush);
console.log("But now we've corrupted Parent.prototype in order to inherit");
console.log(Actor.prototype.age); //11
console.log(Actor.prototype.name); //dhanush

Wracając do oryginalnego pytania jak używać new operator with apply, Oto moje zdanie....

Function.prototype.new = function(){
    var constructor = this;
    function fn() {return constructor.apply(this, args)}
    var args = Array.prototype.slice.call(arguments);
    fn.prototype = this.prototype;
    return new fn
};

var thalaivar = Actor.new.apply(Parent, ["Thalaivar", 30]);
console.log(thalaivar);
 0
Author: Thalaivar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-14 20:11:44

Ponieważ ES6 jest to możliwe poprzez operator spreadu, zobacz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Apply_for_new

Ta odpowiedź była już, tak jakby podana w komentarzu https://stackoverflow.com/a/42027742/7049810 , ale wydaje się, że większość

 0
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25

Właściwie najprostszą metodą jest:

function Something (a, b) {
  this.a = a;
  this.b = b;
}
function createSomething(){
    return Something;
}
s = new (createSomething())(1, 2); 
// s == Something {a: 1, b: 2}
 0
Author: user3184743,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-27 07:53:32

Poprawione rozwiązanie z odpowiedzi @ jordancpaul.

var applyCtor = function(ctor, args)
{
    var instance = new ctor();
    ctor.prototype.constructor.apply(instance, args);
    return instance;
}; 
 0
Author: tech-e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-05 20:14:20

Stwórz anonimowy prototyp i zastosuj do niego prototyp Something używając argumentów, a następnie utwórz nową instancję tego anonimowego prototypu. Jedyną wadą tego jest to, że nie przejdzie kontroli s instanceof Something, chociaż jest identyczna, jest w zasadzie instancją klonu.

function Something(){
    // init stuff
}
function createSomething(){
    return new (function(){Something.apply(this, arguments)});
}
var s = createSomething(a,b,c); // 's' is an instance of Something
 0
Author: Dustin Poissant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-13 19:26:20

Dzięki postom tutaj użyłem go w ten sposób:

SomeClass = function(arg1, arg2) {
    // ...
}

ReflectUtil.newInstance('SomeClass', 5, 7);

I realizacja:

/**
 * @param strClass:
 *          class name
 * @param optionals:
 *          constructor arguments
 */
ReflectUtil.newInstance = function(strClass) {
    var args = Array.prototype.slice.call(arguments, 1);
    var clsClass = eval(strClass);
    function F() {
        return clsClass.apply(this, args);
    }
    F.prototype = clsClass.prototype;
    return new F();
};
 -1
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-04 20:41:58