Constructores en objetos JavaScript
¿Pueden las clases/objetos de JavaScript tener constructores? ¿Cómo se crean?
Usando prototipos:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Ocultar "color" (se parece un poco a una variable miembro privada):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Uso:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
Aquí hay una plantilla que a veces uso para un comportamiento similar a la programación orientada a objetos en JavaScript. Como puede ver, puede simular miembros privados (tanto estáticos como de instancia) mediante cierres. Lo que new MyClass()
devolverá es un objeto con sólo las propiedades asignadas al this
objeto y en el prototype
objeto de la "clase".
var MyClass = (function () {
// private static
var nextId = 1;
// constructor
var cls = function () {
// private
var id = nextId++;
var name = 'Unknown';
// public (this instance only)
this.get_id = function () { return id; };
this.get_name = function () { return name; };
this.set_name = function (value) {
if (typeof value != 'string')
throw 'Name must be a string';
if (value.length < 2 || value.length > 20)
throw 'Name must be 2-20 characters long.';
name = value;
};
};
// public static
cls.get_nextId = function () {
return nextId;
};
// public (shared across instances)
cls.prototype = {
announce: function () {
alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
}
};
return cls;
})();
Me preguntaron sobre la herencia usando este patrón, así que aquí va:
// It's a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
// We use an intermediary empty constructor to create an
// inheritance chain, because using the super class' constructor
// might have side effects.
var construct = function () {};
construct.prototype = superCls.prototype;
cls.prototype = new construct;
cls.prototype.constructor = cls;
cls.super = superCls;
}
var MyChildClass = (function () {
// constructor
var cls = function (surName) {
// Call super constructor on this instance (any arguments
// to the constructor would go after "this" in call(…)).
this.constructor.super.call(this);
// Shadowing instance properties is a little bit less
// intuitive, but can be done:
var getName = this.get_name;
// public (this instance only)
this.get_name = function () {
return getName.call(this) + ' ' + surName;
};
};
inherit(cls, MyClass); // <-- important!
return cls;
})();
Y un ejemplo para usarlo todo:
var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"
var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"
alert(john instanceof MyClass); // true
Como puede ver, las clases interactúan correctamente entre sí (comparten la identificación estática de MyClass
, el announce
método usa el get_name
método correcto, etc.)
Una cosa a tener en cuenta es la necesidad de ocultar las propiedades de la instancia. De hecho, puede hacer que la inherit
función revise todas las propiedades de la instancia (usando hasOwnProperty
) que sean funciones y agregue automáticamente una super_<method name>
propiedad. Esto le permitiría llamar this.super_get_name()
en lugar de almacenarlo en un valor temporal y llamarlo vinculado usando call
.
Para los métodos del prototipo, no necesita preocuparse por lo anterior; si desea acceder a los métodos del prototipo de la superclase, simplemente puede llamar a this.constructor.super.prototype.methodName
. Si desea hacerlo menos detallado, por supuesto puede agregar propiedades de conveniencia. :)
Me parece que la mayoría de ustedes están dando ejemplos de captadores y definidores, no de un constructor, es decir, http://en.wikipedia.org/wiki/Constructor_(object- Oriented_programming) .
lunched-dan estaba más cerca pero el ejemplo no funcionó en jsFiddle.
Este ejemplo crea una función constructora privada que solo se ejecuta durante la creación del objeto.
var color = 'black';
function Box()
{
// private property
var color = '';
// private constructor
var __construct = function() {
alert("Object Created.");
color = 'green';
}()
// getter
this.getColor = function() {
return color;
}
// setter
this.setColor = function(data) {
color = data;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black
Si quisiera asignar propiedades públicas, entonces el constructor podría definirse como tal:
var color = 'black';
function Box()
{
// public property
this.color = '';
// private constructor
var __construct = function(that) {
alert("Object Created.");
that.color = 'green';
}(this)
// getter
this.getColor = function() {
return this.color;
}
// setter
this.setColor = function(color) {
this.color = color;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black