), но передать конструктору произвольное количество аргументов. Это возможно? new Я хочу сделать что-то вроде этого (но код ниже не работает):

Ответ

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

Из ответов здесь стало ясно, что нет встроенного способа вызова

оператор. Тем не менее, люди предложили ряд действительно интересных решений проблемы. .apply() В соответствии с вопросом, пользователю нужен код в javascript вместо jquery, поэтому редактирование будет new Мое предпочтительное решение было

(я изменил его, чтобы передать свойство Это требует новый фет ch API. (): arguments все становится довольно чисто:

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

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

С ECMAScript5 Function.prototype.bind Его можно использовать следующим образом:

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
}

или даже напрямую:

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

Это и

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

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

решение на основе eval для функции, которая принимает ограниченное количество аргументов. Метод — единственные, которые всегда работают, даже со специальными конструкторами, такими как Date:

var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true

I Вместо этого используйте любой из методов, ранее упомянутых другими: свойство

Небольшое объяснение: нам нужно запустить new позволяет нам сделать это следующим образом: параметр bind не имеет большого значения, поскольку ключевое слово

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

Переменная anything сбрасывает контекст new. Однако это требуется по синтаксическим причинам. Теперь, для вызова f: нам нужно передать переменное количество аргументов, так что это делает свое дело: bind Давайте обернем это в функцию.

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

На самом деле, временный Cls будут работать как шарм anything Глядя на вывод

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

действительно то, что нам нужно. (f вообще не нужна:

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

Наконец, мы должны убедиться, что bind может быть перезаписано). Поэтому замените его на Cls.bind, и мы получим окончательный результат, как указано выше. Function.prototype.bind Вот обобщенное решение, которое может вызывать любой конструктор (кроме собственных конструкторов, которые при вызове в качестве функций ведут себя по-разному, например,

будет идентичен объекту, созданному с помощью String, Number, Date и т. Д. ) с массивом аргументов:

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

Объект, созданный с помощью вызова construct(Class, [1, 2, 3]). Вы также можете сделать более конкретную версию, чтобы вы не делали не нужно каждый раз передавать конструктор. Это также немного более эффективно, так как не нужно создавать новый экземпляр внутренней функции каждый раз, когда вы ее вызываете. new Class(1, 2, 3) Глядя на вывод

Причина создания и вызова внешнего анонима Подобная функция не позволяет функции

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

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

загрязнять глобальное пространство имен. Иногда ее называют шаблоном модуля. F Для тех, кто хочет использовать это в TypeScript, поскольку TS выдает ошибку, если

// В приведенном выше коде новый объект со строковым значением создан.

возвращает что-либо: Оператор распространения ECMA Script 2015 (F, вы можете просто использовать его следующим образом

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

Если ваша среда поддерживает Теперь, когда спецификации ECMA Script 2015 опубликованы и большинство движков JavaScript активно его реализуют, это будет предпочтительным способом сделать это. { *} Вы можете проверить поддержку оператора Spread ort в нескольких основных средах, ... С чем вы столкнулись Предположим, у вас есть конструктор Items, который отбрасывает все аргументы, которые вы ему набрасываете:

function Something() {
    // init stuff
}

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

Примечание: Который при запуске печатает 10 с 1 2 3 4 == 10:

В ES6 говорится, что Глядя на вывод

@ Matthew Я думаю, что лучше также исправить свойство конструктора.

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

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

Альтернатива, если вы используете

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

console.log(items.sum());

Это можно использовать, вызвав

$ node t.js
10

. Вы можете переместить инициализацию в отдельный метод прототипа Reflect.construct() Потенциальная проблема:

Reflect.construct(F, args)

:

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

http://jsfiddle.net/Gajotres/VAG6F/

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

Этот ответ немного запоздал, но подумал, что любой, кто увидит это, может использовать это. Есть способ вернуть новый объект, используя apply. Хотя это требует одного небольшого изменения в объявлении вашего объекта. applyCtor(class, [arg1, arg2, argn]);

для работы в Something вы должны

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

обновить:

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;

свойство, указывающее на вашу «анонимную» функцию. В вашем примере вы могли бы использовать if Я изменил свой первый пример, чтобы суммировать любое количество аргументов, а не только два. testNew Смотрите также, как это делает CoffeeScript. return this; внизу функции. В качестве примера с вашим кодом:

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

Это работает! Этот конструкторский подход работает как с ключевым словом

Я только что столкнулся с этой проблемой, и я решил ее следующим образом:

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

Да, это немного уродливо, но это решает проблему, и это очень просто.

если вы заинтересованы в решении на основе eval

function createSomething() {
    var q = [];
    for(var i = 0; i < arguments.length; i  )
        q.push("arguments["   i   "]");
    return eval("new Something("   q.join(",")   ")");
}

, так и без него:

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

Становится:

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(){});

Предполагается поддержка

var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);

, но вы всегда можете сделать это, если вы поддерживаете старые браузеры. new Смотрите таблицу поддержки MDN здесь

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

без Object.create Демо {arg1: «X», arg2: «Y», arg3: «Z»} … или «более коротким» способом: { *} Я думаю, что это может быть хорошим решением: Глядя на вывод

Вот Узел 6 Глядя на вывод

, и, возможно, это не так просто, но лучше, чем ничего. Посмотрите: Вы не можете вызвать конструктор с переменным числом аргументов, как вы хотите с ES6 или полифиллами:

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

Вывод

Демонстрация {arg1: «X», arg2: «Y» , arg3: «Z»}

… или «более коротким» способом:

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

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

Мы только что выпустили
Я думаю, что это может быть хорошим решением:

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

Вы не можете вызывать конструктор с переменным числом аргументов, как вы хотите с помощью new.

вы можете немного изменить конструктор. Вместо:

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

Сделайте это вместо:

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

Или, если вам нужно использовать массив:

function Something(args) {
    var x = args[0];
    var y = args[1];
}
var obj = new Something([0, 0]);

Решения Мэтью Крамли в CoffeeScript:

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

или

createSomething = (->
    F = (args) -> Something.apply this, args
    F.prototype = Something.prototype
    return -> new Something arguments
)()
function createSomething() {
    var args = Array.prototype.concat.apply([null], arguments);
    return new (Function.prototype.bind.apply(Something, args));
}

в JavaScript? Function.prototype.bind код не будет работать. Однако это маловероятно, см. таблица совместимости Глядя на вывод

измененный ответ @Matthew. Здесь я могу передать любое количество параметров, чтобы функционировать как обычно (не массив). Кроме того, что-то не жестко закодировано в: конструкторе

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

Этот однострочник должен сделать это:

new (Function.prototype.bind.apply(Something, [null].concat(arguments)));

форматов даты и времени может быть настроена с помощью аргумента параметров. F(), с помощью arguments.callee, также называемой самой функцией создателя / фабрики: http://www.dhtmlkitchen.com/?category=/JavaScript/ { *.} amp ; date = 2008/05/11 / & amp ; entry = Decorator-Factory-Aspect

Любая функция (даже конструктор) может принимать переменное число аргументы. Каждая функция имеет переменную «arguments», которая может быть приведена к массиву с помощью [].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') );

. Вышеуказанные тесты дают следующий вывод:

s.options === "1,2,3,4": true
z.options === "9,10,11": true
function FooFactory() {
    var prototype, F = function(){};

    function Foo() {
        var args = Array.prototype.slice.call(arguments),
            i;     
        for (i = 0, this.args = {}; i < args.length; i  =1) {
            this.args[i] = args[i];
        }
        this.bar = 'baz';
        this.print();

        return this;
    }

    prototype = Foo.prototype;
    prototype.print = function () {
        console.log(this.bar);
    };

    F.prototype = prototype;

    return Foo.apply(new F(), Array.prototype.slice.call(arguments));
}

var foo = FooFactory('a', 'b', 'c', 'd', {}, function (){});
console.log('foo:',foo);
foo.print();

загрузка AJAX действительно возможна с XMLHttpRequest (). Нет необходимости в фреймах. Процесс загрузки может быть показан. createSomething:

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

Исходя из этого, я попытался смоделировать new 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;
}

Я проверил это, и кажется, что он отлично работает для всех сценариев. Он также работает с нативными конструкторами, такими как Date. Вот несколько тестов:

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

Хотя другие подходы работоспособны, они чрезмерно сложны. В Clojure вы обычно создаете функцию, которая создает экземпляры типов / записей, и используете эту функцию в качестве механизма для создания экземпляров. Перевод этого в JavaScript:

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

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

Используя этот подход, вы избегаете использования new, за исключением случаев, описанных выше. И эта функция, конечно же, не имеет проблем при работе с apply или любое количество других функций функционального программирования.

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

. Используя этот подход, все ваши конструкторы типов (например, Person) являются ванильными, ничего не делающими конструкторами. Вы просто передаете аргументы и присваиваете их свойствам с тем же именем. Волосатые детали идут в функции конструктора (например, person).

Нет необходимости создавать эти дополнительные функции конструктора, так как они в любом случае являются хорошей практикой. Они могут быть удобными, поскольку они позволяют потенциально иметь несколько функций конструктора с различными нюансами .

Да, мы можем, javascript больше похож на prototype inheritance по своей природе.

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

Когда мы создаем объект с «new «тогда наш созданный объект INHERITS getAge (), Но если бы мы использовали apply(...) or call(...) для вызова Actor, тогда мы передаем объект для "this", но объект, который мы передаем WON'T, наследуют от Actor.prototype

, если только мы непосредственно не передадим apply или вызовите Actor.prototype, но тогда …. «this» будет указывать на «Actor.prototype», и this.name будет писать в: Actor.prototype.name У меня есть код, который мне нужно запустить с 160 индивидуально разработанными брендами. Большая часть кода находится в общих файлах, но специфические для брендинга вещи находятся в отдельном файле, по одному для каждого брендинга. Actor..., поскольку мы перезаписываем прототип, а не экземпляр

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

. Давайте попробуем с Передав 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

, поскольку «this» будет указывать на Actor.prototypeActor.call() в качестве первого аргумента, когда функция Actor () запускается, она выполняет this.name=name Возвращаясь к первоначальному вопросу о том, как использовать 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

Возвращаясь к первоначальному вопросу о том, как использовать new operator with apply, вот мой дубль ….

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

после ES6 это возможно с помощью оператора Spread, см. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator # Apply_for_new

Этот ответ был уже вроде как указано в комментарии https://stackoverflow.com/a/42027742/7049810 , но, похоже, большинство его пропустили

На самом деле самый простой способ:

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}

Пересмотренное решение из ответа @ jordancpaul.

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

Спасибо постам здесь я использовал это следующим образом:

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

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

и реализация:

/**
 * @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();
};