Программно создать новый объект - PullRequest
1 голос
/ 03 апреля 2012

Я пытаюсь создать функцию, которая будет принимать аргументы arg1, arg2..., а затем передавать их в конструктор для нового объекта C, например, так: new C(arg1, arg2...), поэтому для создания нового экземпляра C пользователь будет просто иметьпозвонить C(arg) вместо new C(arg).Вот моя первая попытка:

var C = function(a){ this.a = a; }

var Cn = function(){
    new C.apply(this, arguments);
}

Cn(0)     // Should make a new C with a property a equal to 0
new C(0)  // ie the same as this

Редактировать: Обратите внимание, мне нужно принять произвольное количество аргументов и не использовать eval.Я делаю библиотеку, реализующую алгебраических типов данных в js.


Редактировать: Решением было взять Идея Джереми и адаптировать ее для получения неограниченногоколичество аргументов:

var C = function() {

    // A unique object so we can identify when we used the 'newless' constructor
    var newlessConstructorObj = {}

    // Check to see if C has been called with `new`
    if(!(this instanceof C))
        // If not pass arguments as single arg back to C
        return new C(newlessConstructorObj, arguments);


    // Check to see if we got here from the line above, if so the arguments were passed in the second arg
    var args = (arguments[0] === newlessConstructorObj) ? arguments[1] : arguments

    // Do stuff with args
    this.a = args[0];
}

C(0);
new C(0);

Ответы [ 6 ]

2 голосов
/ 03 апреля 2012

Я бы выбрал решение Фабрицио Кальдерана в любой день, но поскольку вам нужна эта конкретная функциональность - вот что говорят нам предшественники:


вы можете применять аргументы к prototype.constructor (но есть проблемыпри выполнении с нативными типами, такими как Number):

var Cn = function(){
    return C.prototype.constructor.apply(C, arguments);
}

Ссылка: Создание экземпляра объекта JavaScript путем вызова prototype.constructor.apply


или.использовать eval:

function construct(Constructor) 
{ 
 /* 
  * or Array.prototype.slice.call(arguments, 1).map(function() { ... }) 
  * in JavaScript 1.6+, compatibles, and with augmented Array.prototype 
  */ 
 var args = []; 
 for (var i = 1, len = arguments.length; i < len; i++) 
 { 
   args[i - 1] = "arguments[" + i + "]"; 
 } 

/* or args.join(", ") if you need it pretty-printed */ 
 return eval("new Constructor(" + args + ")"); 
} 

function Foo() 
{ 
  window.alert(Array.prototype.slice.call(arguments, 0).join(", ")); 
} 

var f = construct(Foo, /bar/g, {baz: 42});

Ссылка: http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/ff1a104bdc33d5c8

2 голосов
/ 03 апреля 2012

Если вы хотите иметь возможность вызывать функцию с новым ключевым словом или без него, вы должны следовать следующему шаблону:

C = function(a) {
  if (!(this instanceof C)) {
    return new C(a);
  }

  this.a = a;
}

, чтобы создать новый экземпляр "C":

c = new C(a);

и

c = C(a);

оба вернут правильно сформированный экземпляр C

1 голос
/ 03 апреля 2012

Сделать это с фиксированным числом аргументов просто:

// assuming one arg
function Cn(arg) {
  return new C(arg);
}

// assuming two args
function Cn(arg0, arg1) {
  return new C(arg0, arg1);
}

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

Но какой в ​​этом смысл? Просто чтобы сохранить набрав 4 символа?

1 голос
/ 03 апреля 2012

Если вам не нужна правильная проверка instanceof, попробуйте следующее:

var C = function(a){ this.a = a; }

var Cn = function(){
    return C.apply({}, arguments); // notice an empty object here
}

Cn(0)     // Should make a new C with a property a equal to 0
new C(0)  // ie the same as this
1 голос
/ 03 апреля 2012

как то так?

var C = function(obj){ 
  var a;
  for (a in obj) {
     this[a] = obj[a]; 
  }
}
var Cn = function(obj) { return new C(obj); }

instance = Cn({
  a : 1,
  b : 2
})  

instance.a //1
instance.b //2
instance.c //undefined
0 голосов
/ 26 марта 2018

Обновлен для ES6, вы можете использовать оператор распространения:

var C = function(a){ this.a = a; }

var Cn = function(...args){
    return new C(...args);
}

assert.deepStrictEqual(Cn(10), new C(10));
...