Использование .apply () с оператором 'new'. Это возможно? - PullRequest
443 голосов
/ 22 октября 2009

В JavaScript я хочу создать экземпляр объекта (с помощью оператора 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() с оператором new. Тем не менее, люди предложили ряд действительно интересных решений этой проблемы.

Мое предпочтительное решение было это от Мэтью Крамли (я изменил его, чтобы передать свойство arguments):

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

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

Ответы [ 35 ]

0 голосов
/ 12 июня 2014

В качестве позднего ответа я решил, что я просто опущу это здесь как более полное решение, используя многие принципы, уже изложенные здесь.

Implements.js

Для начала, вот основное использование:

var a = function(){
    this.propa = 'a';
}
var b = function(){
    this.propb = 'b'
}
var c = Function.Implement(a, b); // -> { propa: 'a', propb: 'b' }
0 голосов
/ 17 декабря 2013
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();
0 голосов
/ 18 сентября 2012

Любая функция (даже конструктор) может принимать переменное количество аргументов. Каждая функция имеет переменную «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
0 голосов
/ 05 марта 2018

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

var applyCtor = function(ctor, args)
{
    var instance = new ctor();
    ctor.prototype.constructor.apply(instance, args);
    return instance;
}; 
0 голосов
/ 13 мая 2014

Вот моя версия 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...