Использование .apply () с оператором 'new'. Это возможно?

Для чего это стоит ...

Нарушение интерфейсов:

interface Imodel {

    static function tableStruct();        
}

abstract class model implements Imodel {

    private static $tableStruct = array();

    public static function foo() {
        if (!isset(self::$tableStruct[get_called_class()]))
            self::$tableStruct[get_called_class()] = static::tableStruct();

        // I'm using it here!!
    }
}
443
задан Prisoner ZERO 6 August 2017 в 15:18
поделиться

5 ответов

Сделайте анонимный прототип и подайте заявку Something прототип к нему с помощью аргументов и затем создайте новый экземпляр того анонимного прототипа. Один disadavantage этого - это, не передаст эти s instanceof Something проверка, хотя это идентично, это - в основном экземпляр клона.

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
ответ дан 22 November 2019 в 23:05
поделиться

You can't call a constructor with a variable number of arguments like you want with the new operator.

What you can do is change the constructor slightly. Instead of:

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

Do this instead:

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

Or if you must use an array:

function Something(args) {
    var x = args[0];
    var y = args[1];
}
var obj = new Something([0, 0]);
1
ответ дан 22 November 2019 в 23:05
поделиться

, если вас интересует решение на основе eval

function createSomething() {
    var q = [];
    for(var i = 0; i < arguments.length; i++)
        q.push("arguments[" + i + "]");
    return eval("new Something(" + q.join(",") + ")");
}
4
ответ дан 22 November 2019 в 23:05
поделиться

Вы можете переместить материал инициализации в отдельный метод прототипа 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
7
ответ дан 22 November 2019 в 23:05
поделиться

Here's a generalized solution that can call any constructor (except native constructors that behave differently when called as functions, like String, Number, Date, etc.) with an array of arguments:

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

An object created by calling construct(Class, [1, 2, 3]) would be identical to an object created with new Class(1, 2, 3).

You could also make a more specific version so you don't have to pass the constructor every time. This is also slightly more efficient, since it doesn't need to create a new instance of the inner function every time you call it.

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

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

The reason for creating and calling the outer anonymous function like that is to keep function F from polluting the global namespace. It's sometimes called the module pattern.

[UPDATE]

For those who want to use this in TypeScript, since TS gives an error if F returns anything:

function construct(constructor, args) {
    function F() : void {
        constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}
259
ответ дан 22 November 2019 в 23:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: