Для чего это стоит ...
Нарушение интерфейсов:
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!!
}
}
Сделайте анонимный прототип и подайте заявку 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
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]);
, если вас интересует решение на основе eval
function createSomething() {
var q = [];
for(var i = 0; i < arguments.length; i++)
q.push("arguments[" + i + "]");
return eval("new Something(" + q.join(",") + ")");
}
Вы можете переместить материал инициализации в отдельный метод прототипа 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
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();
}