tipos - JavaScript: ¿Cómo crear una nueva instancia de una clase sin usar la nueva palabra clave?
prototipos en javascript (6)
¿No funciona esto?
function factory(class_) {
return new class_();
}
No entiendo por qué no puedes usar lo new
.
Creo que el siguiente código aclarará la pregunta.
// My class
var Class = function() { console.log("Constructor"); };
Class.prototype = { method: function() { console.log("Method");} }
// Creating an instance with new
var object1 = new Class();
object1.method();
console.log("New returned", object1);
// How to write a factory which can''t use the new keyword?
function factory(clazz) {
// Assume this function can''t see "Class", but only sees its parameter "clazz".
return clazz.call(); // Calls the constructor, but no new object is created
return clazz.new(); // Doesn''t work because there is new() method
};
var object2 = factory(Class);
object2.method();
console.log("Factory returned", object2);
De otra manera:
var factory = function(clazz /*, arguments*/) {
var args = [].slice.call(arguments, 1);
return new function() {
clazz.apply(this, args)
}
}
Debido a que JavaScript no tiene clases, permítame volver a formular su pregunta: ¿Cómo crear un nuevo objeto basado en un objeto existente sin usar la nueva palabra clave?
Aquí hay un método que no usa "nuevo". No es estrictamente una "nueva instancia de", pero es la única forma de pensar que no usa "nuevo" (y no usa ninguna característica de ECMAScript 5).
//a very basic version that doesn''t use ''new''
function factory(clazz) {
var o = {};
for (var prop in clazz) {
o[prop] = clazz[prop];
}
return o;
};
//test
var clazz = { prop1: "hello clazz" };
var testObj1 = factory(clazz);
console.log(testObj1.prop1); //"hello clazz"
Podría ser elegante y configurar el prototipo, pero luego se mete en problemas con varios navegadores y estoy tratando de mantener esto simple. También es posible que desee utilizar "hasOwnProperty" para filtrar las propiedades que agrega al nuevo objeto.
Hay otras formas que usan "nuevo" pero que lo ocultan. Aquí hay uno que toma prestado de la función Object.create en JavaScript: The Good Parts de Douglas Crockford :
//Another version the does use ''new'' but in a limited sense
function factory(clazz) {
var F = function() {};
F.prototype = clazz;
return new F();
};
//Test
var orig = { prop1: "hello orig" };
var testObj2 = factory(orig);
console.log(testObj2.prop1); //"hello orig"
EcmaScript 5 tiene el método Object.create que lo hará mucho mejor, pero solo es compatible con los navegadores más nuevos (por ejemplo, IE9, FF4), pero puede usar un polyfill (algo que llena las grietas), como ES5 Shim , para obtener una implementación para los navegadores más antiguos. (Consulte el artículo de John Resig sobre las nuevas características de ES5, incluido Object.create ).
En ES5 puedes hacerlo así:
//using Object.create - doesn''t use "new"
var baseObj = { prop1: "hello base" };
var testObj3 = Object.create(baseObj);
console.log(testObj3.prop1);
Espero que eso ayude
Si realmente no quiere usar la new
palabra clave y no le importa que solo sea compatible con Firefox, puede configurar el prototipo usted mismo. Sin embargo, esto no tiene ningún sentido, ya que puedes usar la respuesta de Dave Hinton.
// This is essentially what the new keyword does
function factory(clazz) {
var obj = {};
obj.__proto__ = clazz.prototype;
var result = clazz.call(obj);
return (typeof result !== ''undefined'') ? result : obj;
};
Supongo que la solución independiente del navegador sería mejor
function empty() {}
function factory(clazz /*, some more arguments for constructor */) {
empty.prototype = clazz.prototype;
var obj = new empty();
clazz.apply(obj, Array.prototype.slice.call(arguments, 1));
return obj;
}
Una forma más simple, limpia y sin "fábricas".
function Person(name) {
if (!(this instanceof Person)) return new Person(name);
this.name = name;
}
var p1 = new Person(''Fred'');
var p2 = Person(''Barney'');
p1 instanceof Person //=> true
p2 instanceof Person //=> true