objetos - prototype javascript ejemplos
Constructores en objetos JavaScript (19)
Entonces, ¿cuál es el punto de propiedad "constructor"? No se puede averiguar dónde podría ser útil, alguna idea?
El punto de la propiedad del constructor es proporcionar alguna forma de simular que JavaScript tiene clases. Una de las cosas que no puedes hacer útil es cambiar el constructor de un objeto después de que se haya creado. Es complicado.
Escribí un artículo bastante completo sobre él hace unos años: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
¿Pueden las clases / objetos de JavaScript tener constructores? ¿Cómo se crean?
Aquí debemos notar un punto en el script java, sin embargo, es un lenguaje sin clase, podemos lograrlo mediante el uso de funciones en el script java. La forma más común de lograr esto es que necesitamos 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 un 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
Aquí hay una plantilla que a veces uso para un comportamiento similar a OOP en JavaScript. Como puede ver, puede simular miembros privados (tanto estáticos como de instancia) utilizando cierres. Lo que new MyClass()
devolverá es un objeto con solo las propiedades asignadas a this
objeto y en el objeto prototype
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 han preguntado 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 método de announce
utiliza el método correcto de get_name
, etc.)
Una cosa a tener en cuenta es la necesidad de sombrear las propiedades de la instancia. En realidad, puede hacer que la función hasOwnProperty
pase por todas las propiedades de la instancia (utilizando hasOwnProperty
) que son funciones, y agregar super_<method name>
una super_<method name>
. Esto le permitiría llamar a this.super_get_name()
lugar de almacenarlo en un valor temporal y llamarlo vinculado usando call
.
Para los métodos del prototipo, no necesita preocuparse por lo anterior, sin embargo, si desea acceder a los métodos del prototipo de la súper clase, puede llamar a this.constructor.super.prototype.methodName
. Si desea que sea menos detallado, por supuesto puede agregar propiedades de conveniencia. :)
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>
Ejemplo de clase:
<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 de elementos de inspección de Chrome, ejecute este script y expanda el seguimiento 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>
En JavaScript, el tipo de invocación define el comportamiento de la función:
- Función de invocación directa
func()
- Invocación del método en un objeto
obj.func()
- Constructor invocación
new func()
- Invocación indirecta
func.call()
ofunc.apply()
La función se invoca como un constructor cuando se llama utilizando un 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 o objeto prototipo en JavaScript tiene un constructor
propiedades, que se refiere a la función de constructor.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Revisa esta publicación sobre la propiedad del constructor.
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 pase esta información. Si no tiene que establecer inicialmente una propiedad, simplemente puede llamar a un método dentro del objeto como tal. Probablemente no sea la forma más bonita de hacer esto, pero esto todavía funciona.
var objectA = {
color: '''';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();
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.
Este patrón me ha servido bien. Con este patrón, crea clases en archivos separados, los carga 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");
He encontrado 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]"
Lo hacen si usa Typescript - código abierto de MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Typescript le permite "falsificar" construcciones OO que se compilan en construcciones javascript. Si está comenzando un proyecto grande, puede ahorrarle mucho tiempo y solo alcanzó la versión 1.0 del hito.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
El código anterior se ''compila'' a:
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
Me parece que la mayoría de ustedes está dando ejemplos de captadores y configuradores, 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 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, 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
Mientras utilizaba la gran plantilla de Blixt de arriba, descubrí que no funciona bien con la herencia de múltiples niveles (MyGrandChildClass extendiendo MyChildClass extendiendo MyClass) - cicla en llamar al constructor del primer padre una y otra vez. Así que aquí hay una solución alternativa simple: si necesita herencia multinivel, en lugar de usar this.constructor.super.call(this, surName);
use chainSuper(this).call(this, surName);
con la función de cadena definida así:
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;
}
Sí, puedes definir un constructor dentro de una declaración de clase como esta:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Sólo para ofrecer algo de variedad. ds.oop es una buena forma de declarar clases con constructores en javascript. Admite todos los tipos posibles de herencia (incluido 1 tipo que incluso c # no admite), así como 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
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);
}
};
};
Los comentarios y sugerencias a esta solución son bienvenidos. :)
Tal vez se haya vuelto un poco más simple, pero a continuación es lo que he encontrado 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 funciones de establecimiento y probamos que su cambio se mantuvo al llamar a getInfo()
después de estos cambios.
Un poco tarde, pero espero que esto ayude. He probado esto con una unidad de mocha
, y está funcionando bien.
Usando el ejemplo 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 __construir 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();
Utilizando prototipos:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Ocultar "color" (se asemeja algo 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
http://www.jsoops.net/ es bastante bueno para oop en Js. Si se proporciona privado, protegido, variable y función pública, y también 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