¿Pueden las clases / objetos JavaScript tener constructores? ¿Cómo se crean?
¿Pueden las clases / objetos JavaScript tener constructores? ¿Cómo se crean?
Respuestas:
Usando prototipos:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Ocultar "color" (algo parecido a una variable de miembro privado):
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
color
. Te sugiero que uses en gran medida por preferencia personal (protección versus simplicidad)
var
hace una variable privada. this
hace una variable pública
Foo
, mientras que en el último caso sabrá que se Foo
está llamando. Muy útil para la depuración.
Aquí hay una plantilla que a veces uso para comportamientos similares a OOP en JavaScript. Como puede ver, puede simular miembros privados (tanto estáticos como de instancia) utilizando cierres. Lo new MyClass()
que devolverá es un objeto con solo 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 MyClass
, el announce
método usa el get_name
método correcto , etc.)
Una cosa a tener en cuenta es la necesidad de sombrear las propiedades de instancia. En realidad, puede hacer que la inherit
función pase por todas las propiedades de instancia (usando hasOwnProperty
) que son funciones, y agregar automáticamente una super_<method name>
propiedad. Esto le permitiría llamar en this.super_get_name()
lugar de almacenarlo en un valor temporal y llamarlo enlazado usando call
.
Sin embargo, para los métodos en el prototipo no necesita preocuparse por lo anterior, si desea acceder a los métodos prototipo de la superclase, simplemente puede llamar this.constructor.super.prototype.methodName
. Si desea que sea menos detallado, por supuesto, puede agregar propiedades de conveniencia. :)
cls.prototype
parte: "compartido entre instancias" es solo para leer el valor (llamar announce
). Si establece myClassInstance.announce
otro valor, crea una nueva propiedad en myClassInstance
, por lo que solo se aplica a ese objeto, no a otras instancias de la clase. MyClass.prototype.announce
Sin embargo, asignar a afectará a todas las instancias.
MyClass.get_nextId()
Me parece que la mayoría de ustedes están dando ejemplos de getters y setters que no son constructores, 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 de constructor privado 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 desea 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
Box()
función :). Pero este ejemplo, así como los ejemplos en las otras respuestas, pueden extenderse fácilmente para aceptar parámetros.
Box
función y estará listo (todavía es "privado"). "Privado" en Javascript solo significa accesible a través del alcance léxico; No es necesario asignar a los miembros. Además: este código está mal. Crea una __construct
variable global , que es bastante mala. var
debe usarse para restringir el alcance de __construct
.
Entonces, ¿cuál es el punto de la propiedad "constructor"? ¿No puede averiguar dónde podría ser útil, alguna idea?
El objetivo de la propiedad del constructor es proporcionar alguna forma de pretender que JavaScript tiene clases. Una de las cosas que no puede hacer es cambiar el constructor de un objeto después de haberlo creado. Es complicado.
Escribí un artículo bastante completo sobre él hace unos años: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Ejemplo aquí: http://jsfiddle.net/FZ5nC/
Prueba esta plantilla:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Name = Name||{};
Name.Space = Name.Space||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Name.Space.ClassName = function Name_Space_ClassName(){}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Name.Space.ClassName.prototype = {
v1: null
,v2: null
,f1: function Name_Space_ClassName_f1(){}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Name.Space.ClassName.staticVar = 0;
//============================================================
// Static Functions
//------------------------------------------------------------
Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
}
</script>
Debe ajustar su espacio de nombres si está definiendo una clase estática:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Clase de ejemplo:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Shape.Rectangle = function Shape_Rectangle(width, height, color){
this.Width = width;
this.Height = height;
this.Color = color;
}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Shape.Rectangle.prototype = {
Width: null
,Height: null
,Color: null
,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
context.fillStyle = this.Color;
context.fillRect(x, y, this.Width, this.Height);
}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Shape.Rectangle.Sides = 4;
//============================================================
// Static Functions
//------------------------------------------------------------
Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
return new Shape.Rectangle(5,8,'#0000ff');
}
Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
return new Shape.Rectangle(50,25,'#ff0000');
}
</script>
Ejemplo de instanciación:
<canvas id="painting" width="500" height="500"></canvas>
<script>
alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");
var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
r1.Draw("painting",0, 20);
var r2 = Shape.Rectangle.CreateSmallBlue();
r2.Draw("painting", 0, 0);
Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
</script>
Las funciones de aviso se definen como AB = función A_B (). Esto es para hacer que su script sea más fácil de depurar. Abra el panel Inspeccionar elemento de Chrome, ejecute este script y expanda la traza inversa de depuración:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
Este es un constructor:
function MyClass() {}
Cuando tu lo hagas
var myObj = new MyClass();
MyClass
se ejecuta y se devuelve un nuevo objeto de esa clase.
alert(valuePassedInAsArgument);
y esto se ejecutará una vez para cada instanciación, por lo que toda la clase es el propio constructor.
new object is returned of that class
- ¿No es más como un nuevo objeto devuelto de esa función?
Encontré este tutorial muy útil. Este enfoque es utilizado por la mayoría de los complementos de jQuery.
var Class = function(methods) {
var klass = function() {
this.initialize.apply(this, arguments);
};
for (var property in methods) {
klass.prototype[property] = methods[property];
}
if (!klass.prototype.initialize) klass.prototype.initialize = function(){};
return klass;
};
Ahora ,
var Person = Class({
initialize: function(name, age) {
this.name = name;
this.age = age;
},
toString: function() {
return "My name is "+this.name+" and I am "+this.age+" years old.";
}
});
var alice = new Person('Alice', 26);
alert(alice.name); //displays "Alice"
alert(alice.age); //displays "26"
alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
//IE 8 and below display the Object's toString() instead! "[Object object]"
klass
Este patrón me ha servido bien. Con este patrón, puede crear clases en archivos separados, cargarlos en su aplicación general "según sea necesario".
// Namespace
// (Creating new if not instantiated yet, otherwise, use existing and just add to it)
var myApp = myApp || {};
// "Package"
// Similar to how you would establish a package in other languages
(function() {
// "Class"
var MyClass = function(params) {
this.initialize(params);
}
// "Private Static" vars
// - Only accessible to functions in this class.
// - Doesn't get wiped out when we create a new instance.
var countInstances = 0;
var allInstances = [];
// "Private Static" functions
// - Same as above, but it's a function accessible
// only to other functions in this class.
function doSomething(){
}
// "Public Static" vars
// - Everyone has access.
// - Doesn't get wiped out when we create a new instance.
MyClass.counter = 0;
// "Public Static" functions
// - Same as above, but anyone can call this "static method".
// - Kinda like a singleton class situation.
MyClass.foobar = function(){
}
// Public properties and methods are built into the "prototype"
// - This is how each instance can become unique unto itself.
// - Establishing "p" as "local" (Static Private) variable
// simply so we don't have to keep typing "MyClass.prototype"
// for each property and function.
var p = MyClass.prototype;
// "Public" vars
p.id = null;
p.firstname = null;
p.lastname = null;
// "Private" vars
// - Only used by "this" instance.
// - There isn't "true" privacy for each
// instance so we have to fake it.
// - By tradition, we indicate "privacy"
// by prefixing it with an underscore.
// - So technically, anyone can access, but we simply
// don't tell anyone about it (e.g. in your API)
// so no one knows about it :)
p._foo = null;
p.initialize = function(params){
this.id = MyClass.counter++;
this.firstname = params.firstname;
this.lastname = params.lastname;
MyClass.counter++;
countInstances++;
allInstances.push(this);
}
p.doAlert = function(theMessage){
alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ". Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
}
// Assign class to app
myApp.MyClass = MyClass;
// Close the "Package"
}());
// Usage example:
var bob = new myApp.MyClass({ firstname : "bob",
lastname : "er"
});
bob.doAlert("hello there");
var
en el constructor (o argumento de función, o en una función similar a un constructor).
Sí, puede definir un constructor dentro de una declaración de clase como esta:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Supongo que publicaré lo que hago con el cierre de JavaScript ya que nadie está usando el cierre todavía.
var user = function(id) {
// private properties & methods goes here.
var someValue;
function doSomething(data) {
someValue = data;
};
// constructor goes here.
if (!id) return null;
// public properties & methods goes here.
return {
id: id,
method: function(params) {
doSomething(params);
}
};
};
Comentarios y sugerencias a esta solución son bienvenidos. :)
Usando la muestra de Nick anterior, puede crear un constructor para objetos sin parámetros usando una declaración de retorno como la última declaración en su definición de objeto. Devuelva su función de constructor como se muestra a continuación y ejecutará el código en __construct cada vez que cree el objeto:
function Box()
{
var __construct = function() {
alert("Object Created.");
this.color = 'green';
}
this.color = '';
this.getColor = function() {
return this.color;
}
__construct();
}
var b = new Box();
this.getColor();
en la línea de arriba, alert("Object Created.");
nada será alertado. Habrá un error como "getColor no está definido". Si desea construir para poder llamar a otros métodos en el objeto, debe definirse después de todos los demás métodos. Entonces, en lugar de llamar __construct();
a la última línea, simplemente defina la construcción allí y colóquela ()
para forzarla a ejecutarse automáticamente.
()
al final de la definición de construcción __ todavía resultó en el error. Tuve que llamar __construct();
a su propia línea como en el código original para evitar el error.
Tal vez se ha vuelto un poco más simple, pero a continuación es lo que se me ocurrió ahora en 2017:
class obj {
constructor(in_shape, in_color){
this.shape = in_shape;
this.color = in_color;
}
getInfo(){
return this.shape + ' and ' + this.color;
}
setShape(in_shape){
this.shape = in_shape;
}
setColor(in_color){
this.color = in_color;
}
}
Al usar la clase anterior, tengo lo siguiente:
var newobj = new obj('square', 'blue');
//Here, we expect to see 'square and blue'
console.log(newobj.getInfo());
newobj.setColor('white');
newobj.setShape('sphere');
//Since we've set new color and shape, we expect the following: 'sphere and white'
console.log(newobj.getInfo());
Como puede ver, el constructor toma dos parámetros y establecemos las propiedades del objeto. También modificamos el color y la forma del objeto mediante el uso de las setter
funciones, y demostramos que su cambio se mantuvo al llamar getInfo()
después de estos cambios.
Un poco tarde, pero espero que esto ayude. He probado esto con una mocha
unidad de prueba, y está funcionando bien.
Lo hacen si usa Typecript - código abierto de MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
El mecanografiado le permite construcciones OO 'falsas' que se compilan en construcciones javascript. Si está comenzando un proyecto grande, puede ahorrarle mucho tiempo y alcanzar la versión 1.0 de hito.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
El código anterior se 'compila' para:
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
En JavaScript, el tipo de invocación define el comportamiento de la función:
func()
obj.func()
new func()
func.call()
ofunc.apply()
La función se invoca como un constructor cuando se llama utilizando el new
operador:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Cualquier instancia u objeto prototipo en JavaScript tiene una propiedad constructor
, que se refiere a la función constructora.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Consulte esta publicación sobre la propiedad del constructor.
Al usar la gran plantilla de Blixt desde arriba, descubrí que no funciona bien con la herencia de varios niveles (MyGrandChildClass extendiendo MyChildClass extendiendo MyClass): se alterna al llamar al constructor del primer padre una y otra vez. Así que aquí hay una solución simple: si necesita una herencia de varios niveles, en lugar de this.constructor.super.call(this, surName);
usarla chainSuper(this).call(this, surName);
con la función de cadena definida de esta manera:
function chainSuper(cls) {
if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
var depth = cls.__depth;
var sup = cls.constructor.super;
while (depth > 1) {
if (sup.super != undefined) sup = sup.super;
depth--;
}
return sup;
}
http://www.jsoops.net/ es bastante bueno para oop en Js. Si proporciona una función y variable privada, protegida y pública, y también la característica de herencia. Código de ejemplo:
var ClassA = JsOops(function (pri, pro, pub)
{// pri = private, pro = protected, pub = public
pri.className = "I am A ";
this.init = function (var1)// constructor
{
pri.className += var1;
}
pub.getData = function ()
{
return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
+ ", ID=" + pro.getClassId() + ")";
}
pri.getClassName = function () { return pri.className; }
pro.getClassName = function () { return pri.className; }
pro.getClassId = function () { return 1; }
});
var newA = new ClassA("Class");
//***Access public function
console.log(typeof (newA.getData));
// function
console.log(newA.getData());
// ClassA(Top=I am A Class, This=I am A Class, ID=1)
//***You can not access constructor, private and protected function
console.log(typeof (newA.init)); // undefined
console.log(typeof (newA.className)); // undefined
console.log(typeof (newA.pro)); // undefined
console.log(typeof (newA.getClassName)); // undefined
solo para ofrecer algo de variedad. ds.oop es una buena manera de declarar clases con constructores en javascript. Admite todos los tipos posibles de herencia (incluido 1 tipo que incluso c # no admite), así como las interfaces, lo cual es bueno.
var Color = ds.make.class({
type: 'Color',
constructor: function (r,g,b) {
this.r = r; /* now r,g, and b are available to */
this.g = g; /* other methods in the Color class */
this.b = b;
}
});
var red = new Color(255,0,0); // using the new keyword to instantiate the class
Aquí necesitamos notar un punto en el script java, es un lenguaje sin clase, sin embargo, podemos lograrlo usando funciones en el script java. La forma más común de lograr esto es crear una función en el script java y usar una nueva palabra clave para crear un objeto y usar esta palabra clave para definir propiedades y métodos. A continuación se muestra el ejemplo.
// Function constructor
var calculator=function(num1 ,num2){
this.name="This is function constructor";
this.mulFunc=function(){
return num1*num2
};
};
var objCal=new calculator(10,10);// This is a constructor in java script
alert(objCal.mulFunc());// method call
alert(objCal.name);// property call
//Constructors With Prototypes
var calculator=function(){
this.name="Constructors With Prototypes";
};
calculator.prototype.mulFunc=function(num1 ,num2){
return num1*num2;
};
var objCal=new calculator();// This is a constructor in java script
alert(objCal.mulFunc(10,10));// method call
alert(objCal.name); // property call
En la mayoría de los casos, debe declarar de alguna manera la propiedad que necesita antes de poder llamar a un método que pasa esta información. Si no tiene que establecer inicialmente una propiedad, puede llamar a un método dentro del objeto de esta manera. Probablemente no sea la forma más bonita de hacerlo, pero aún funciona.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();