Le classi / gli oggetti JavaScript possono avere costruttori? Come vengono creati?
Le classi / gli oggetti JavaScript possono avere costruttori? Come vengono creati?
Risposte:
Utilizzando prototipi:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Nascondere "color" (ricorda in qualche modo una variabile membro privata):
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. Suggerirei che usi in gran parte in base alle preferenze personali (protezione contro semplicità)
varcrea una variabile privata. thisrende una variabile pubblica
Foo, mentre in quest'ultimo caso saprà che Fooviene chiamata. Molto utile per il debug.
Ecco un modello che a volte utilizzo per comportamenti simili a OOP in JavaScript. Come puoi vedere, puoi simulare membri privati (sia statici che di istanza) usando le chiusure. Ciò new MyClass()che restituirà è un oggetto con solo le proprietà assegnate thisall'oggetto e prototypeall'oggetto della "classe".
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;
})();
Mi è stato chiesto dell'ereditarietà usando questo modello, quindi ecco qui:
// 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;
})();
E un esempio per usarlo tutto:
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
Come puoi vedere, le classi interagiscono correttamente tra loro (condividono l'id statico MyClass, il announcemetodo utilizza il get_namemetodo corretto , ecc.)
Una cosa da notare è la necessità di ombreggiare le proprietà dell'istanza. Puoi effettivamente far inheritpassare la funzione attraverso tutte le proprietà dell'istanza (usando hasOwnProperty) che sono funzioni e aggiungere automagicamente una super_<method name>proprietà. Questo ti permetterebbe di chiamare this.super_get_name()invece di memorizzarlo in un valore temporaneo e chiamarlo associato usando call.
Per i metodi sul prototipo non devi preoccuparti di quanto sopra, tuttavia, se vuoi accedere ai metodi prototipo della super classe, puoi semplicemente chiamare this.constructor.super.prototype.methodName. Se vuoi renderlo meno dettagliato puoi ovviamente aggiungere proprietà di convenienza. :)
cls.prototypeparte: "condivisa su più istanze" serve solo per leggere il valore (chiamata announce). Se si imposta myClassInstance.announcesu un altro valore, crea una nuova proprietà in myClassInstance, quindi si applica solo a quell'oggetto, non ad altre istanze della classe. L'assegnazione a MyClass.prototype.announceinteresserà comunque tutte le istanze.
MyClass.get_nextId()
Mi sembra che molti di voi stiano dando esempi di getter e setter, non un costruttore, ad esempio http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .
lunched-dan era più vicino ma l'esempio non funzionava in jsFiddle.
In questo esempio viene creata una funzione di costruzione privata che viene eseguita solo durante la creazione dell'oggetto.
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
Se si desidera assegnare proprietà pubbliche, il costruttore potrebbe essere definito come tale:
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()funzione :). Ma questo esempio così come gli esempi nelle altre risposte possono essere facilmente estesi per accettare i parametri.
Boxfunzione e sei a posto (è ancora "privato"). "Privato" in Javascript significa semplicemente accessibile tramite ambito lessicale; non è necessario assegnare ai membri. Inoltre: questo codice è sbagliato. Crea una __constructvariabile globale , che è piuttosto male. vardovrebbe essere usato per limitare la portata di __construct.
Allora, qual è il punto della proprietà "costruttore"? Non riesci a capire dove potrebbe essere utile, qualche idea?
Il punto della proprietà del costruttore è fornire un modo per fingere che JavaScript abbia delle classi. Una delle cose che non puoi fare utilmente è cambiare il costruttore di un oggetto dopo che è stato creato. È complicato.
Ne ho scritto un pezzo abbastanza completo alcuni anni fa: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Esempio qui: http://jsfiddle.net/FZ5nC/
Prova questo modello:
<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>
Devi adattare il tuo spazio dei nomi se stai definendo una classe statica:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Classe di esempio:
<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>
Esempio di istanza:
<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>
Le funzioni di avviso sono definite come AB = funzione A_B (). Questo per facilitare il debug del tuo script. Apri il pannello Inspect Element di Chrome, esegui questo script ed espandi il backtrace di debug:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
Questo è un costruttore:
function MyClass() {}
Quando lo fai
var myObj = new MyClass();
MyClass viene eseguito e viene restituito un nuovo oggetto di quella classe.
alert(valuePassedInAsArgument);e questo verrà eseguito una volta per ogni istanza, quindi l'intera classe è il costruttore stesso.
new object is returned of that class- non è più come un nuovo oggetto restituito da quella funzione?
Ho trovato questo tutorial molto utile. Questo approccio è utilizzato dalla maggior parte dei plug-in 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;
};
Adesso ,
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
Questo modello mi ha servito bene. Con questo modello, crei le classi in file separati, caricandole nella tua app generale "secondo necessità".
// 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");
varnel costruttore (o argomento di funzione, o in una funzione simile a un costruttore).
Sì, puoi definire un costruttore all'interno di una dichiarazione di classe come questa:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Immagino che posterò quello che faccio con la chiusura di JavaScript poiché nessuno sta ancora usando la chiusura.
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);
}
};
};
Commenti e suggerimenti per questa soluzione sono i benvenuti. :)
Usando l'esempio di Nick sopra, puoi creare un costruttore per oggetti senza parametri usando un'istruzione return come ultima istruzione nella definizione dell'oggetto. Restituisce la funzione di costruzione come di seguito e eseguirà il codice in __construct ogni volta che si crea l'oggetto:
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();sulla riga sopra alert("Object Created.");nulla verrà avvisato. Ci sarà un errore come "getColor non è definito". Se si desidera che il costrutto sia in grado di chiamare altri metodi nell'oggetto, è necessario definirlo dopo tutti gli altri metodi. Quindi, invece di chiamare __construct();l'ultima riga, definisci il costrutto laggiù e mettilo ()dopo per costringerlo ad eseguire automaticamente.
()alla fine della definizione __construct ha comunque comportato l'errore. Ho dovuto chiamare __construct();sulla propria linea come nel codice originale per evitare l'errore.
Forse è diventato un po 'più semplice, ma di seguito è quello che ho escogitato ora nel 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;
}
}
Nell'usare la classe sopra, ho il seguente:
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());
Come puoi vedere, il costruttore accetta due parametri e impostiamo le proprietà dell'oggetto. Modifichiamo anche il colore e la forma dell'oggetto usando le setterfunzioni, e dimostriamo che il suo cambiamento è rimasto su chiamata getInfo()dopo questi cambiamenti.
Un po 'in ritardo, ma spero che questo aiuti. L'ho testato con un mochatest unitario e funziona bene.
Lo fanno se usi Typescript - open source da MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Typescript ti consente di creare falsi costrutti OO che vengono compilati in costrutti javascript. Se stai avviando un grande progetto, potrebbe farti risparmiare un sacco di tempo e ha appena raggiunto il traguardo della versione 1.0.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
Il codice sopra viene 'compilato' per:
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
In JavaScript il tipo di invocazione definisce il comportamento della funzione:
func()obj.func()new func()func.call()ofunc.apply()La funzione viene invocata come costruttore quando si chiama usando l' newoperatore:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Qualsiasi istanza o oggetto prototipo in JavaScript ha una proprietà constructor, che fa riferimento alla funzione di costruzione.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Controlla questo post sulla proprietà del costruttore.
Mentre utilizzavo il grande modello di Blixt dall'alto, ho scoperto che non funziona bene con l'ereditarietà multi-livello (MyGrandChildClass che estende MyChildClass che estende MyClass) - scorre ciclicamente chiamando ripetutamente il costruttore del primo genitore. Quindi ecco una semplice soluzione: se hai bisogno di ereditarietà multi-livello, invece di usare l' this.constructor.super.call(this, surName);uso chainSuper(this).call(this, surName);con la funzione catena definita in questo modo:
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/ è abbastanza buono per oop in Js. Se forniscono funzioni e variabili private, protette, pubbliche e anche ereditarietà. Codice di esempio:
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 per offrire un po 'di varietà. ds.oop è un bel modo per dichiarare le classi con i costruttori in javascript. Supporta tutti i possibili tipi di ereditarietà (incluso 1 tipo che anche c # non supporta) così come le interfacce che sono belle.
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
Qui dobbiamo notare un punto nello script java, è un linguaggio senza classi, tuttavia possiamo ottenerlo utilizzando le funzioni nello script java. Il modo più comune per raggiungere questo obiettivo è necessario creare una funzione nello script java e utilizzare una nuova parola chiave per creare un oggetto e utilizzare questa parola chiave per definire proprietà e metodi. Di seguito è l'esempio.
// 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
Nella maggior parte dei casi è necessario in qualche modo dichiarare la proprietà necessaria prima di poter chiamare un metodo che passa queste informazioni. Se non è necessario impostare inizialmente una proprietà, è possibile chiamare un metodo all'interno dell'oggetto in questo modo. Probabilmente non è il modo più carino di farlo, ma funziona ancora.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();