Costruttori in oggetti JavaScript

Le classi / oggetti JavaScript possono avere costruttori? Come vengono creati?

Utilizzo dei prototipi:

function Box(color) // Constructor { this.color = color; } Box.prototype.getColor = function() { return this.color; }; 

Nascondere “colore” (assomiglia in qualche modo a 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 

Ecco un modello che a volte uso per OOP-comportamento simile in JavaScript. Come puoi vedere, puoi simulare membri privati ​​(sia statici che di istanza) usando le chiusure. Quale new MyClass() restituirà è un object con solo le proprietà assegnate a this object e nell’object prototype della “class”.

 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 di MyClass , il metodo announce usa il metodo get_name corretto, ecc.)

Una cosa da notare è la necessità di ombreggiare le proprietà dell'istanza. È ansible rendere effettivamente la funzione inherit passare attraverso tutte le proprietà dell'istanza (utilizzando hasOwnProperty ) che sono funzioni e aggiungere automaticamente una proprietà super_ . Ciò ti consente di chiamare this.super_get_name() invece di memorizzarlo in un valore temporaneo e chiamarlo associato utilizzando la call .

Per i metodi sul prototipo non è necessario preoccuparsi di quanto sopra, tuttavia, se si desidera accedere ai metodi prototipo di super class, è sufficiente chiamare this.constructor.super.prototype.methodName . Se vuoi renderlo meno dettagliato, puoi ovviamente aggiungere proprietà di convenienza. 🙂

Mi sembra che molti di voi stiano dando esempi di getter e setter non di un costruttore, ovvero http://en.wikipedia.org/wiki/Constructor_(object-orientated_programming) .

lunched-dan era più vicino ma l’esempio non funzionava in jsFiddle.

Questo esempio crea una funzione di costruzione privata che viene eseguita solo durante la creazione dell’object.

 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 

Allora, qual è il punto di proprietà del “costruttore”? Non riesci a capire dove potrebbe essere utile, qualche idea?

Il punto della proprietà del costruttore è di fornire un modo per fingere che JavaScript abbia classi. Una delle cose che non puoi fare utilmente è cambiare il costruttore di un object dopo che è stato creato. È complicato.

Ho scritto un pezzo abbastanza completo su di esso alcuni anni fa: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html

Esempio qui: http://jsfiddle.net/FZ5nC/

Prova questo modello:

  

È necessario regolare lo spazio dei nomi se si definisce una class statica:

  

Classe di esempio:

  

Esempio di istanziazione:

   

Le funzioni di avviso sono definite come AB = funzione A_B (). Questo per rendere il tuo script più facile da eseguire il debug. Apri il pannello Controlla elemento di Chrome, esegui questo script ed espandi il backtrace di debug:

  

Questo è un costruttore:

 function MyClass() {} 

Quando lo fai

 var myObj = new MyClass(); 

MyClass viene eseguito e viene restituito un nuovo object di quella class.

Ho trovato questo tutorial molto utile. Questo approccio è utilizzato dalla maggior parte dei plug-in jQuery.

http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript-class-constructor.html#fbid=OVYAQL_TDpK

 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]" 

Questo schema mi ha servito bene. Con questo modello, puoi creare classi in file separati, caricarli nell’app generale “se necessario”.

 // 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 (eg 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"); 

Sì, puoi definire un costruttore all’interno di una dichiarazione di class 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 a questa soluzione sono i benvenuti. 🙂

Utilizzando l’esempio di Nick sopra, è ansible creare un costruttore per oggetti senza parametri usando un’istruzione return come ultima istruzione nella definizione dell’object. Restituisce la funzione del costruttore come sotto e eseguirà il codice in __Construct ogni volta che crei l’object:

 function Box() { var __construct = function() { alert("Object Created."); this.color = 'green'; } this.color = ''; this.getColor = function() { return this.color; } __construct(); } var b = new Box(); 

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 permette di build costrutti OO ‘falsi’ compilati in costrutti javascript. Se stai iniziando un progetto di grandi dimensioni, potrebbe farti risparmiare un sacco di tempo e ha appena raggiunto la versione milestone 1.0.

http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf

Il codice sopra riportato 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; })(); 

Forse è diventato un po ‘più semplice, ma di seguito è quello che ho scoperto 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 class di cui 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 prende due parametri e impostiamo le proprietà dell’object. Modifichiamo anche il colore e la forma dell’object usando le funzioni setter e getInfo() che il suo cambiamento è rimasto al richiamo di getInfo() dopo queste modifiche.

Un po ‘tardi, ma spero che questo aiuti. Ho provato questo con un test di unità di mocha , e sta funzionando bene.

In JavaScript il tipo di chiamata definisce il comportamento della funzione:

  • Funzione di func() diretta func()
  • Invocazione del metodo su un object obj.func()
  • Funzione di invocazione del costruttore new func()
  • Invocazione indiretta func.call() o func.apply()

La funzione viene invocata come costruttore quando si chiama utilizzando un new operatore:

 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 prototipo di object in JavaScript hanno un constructor proprietà, che fa riferimento alla funzione di costruzione.

 Cat.prototype.constructor === Cat // => true myCat.constructor === Cat // => true 

Controlla questo post sulla proprietà del costruttore.

Durante l’utilizzo dell’ottimo modello di Blixt dall’alto, ho scoperto che non funziona bene con l’ereditarietà multi-livello (MyGrandChildClass che estende MyChildClass estendendo MyClass) – cicla su chiamare il costruttore del primo genitore più e più volte. Quindi ecco una soluzione semplice: se hai bisogno di ereditarietà multi-livello, invece di usare this.constructor.super.call(this, surName); usa chainSuper(this).call(this, surName); con la funzione chain 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 fornisci funzioni e variabili pubbliche, protette, pubbliche e anche di 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 una certa varietà. ds.oop è un buon modo per dichiarare le classi con i costruttori in javascript. Supporta ogni tipo ansible di ereditarietà (incluso un tipo che anche C # non supporta) e Interfacce che è bello.

 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 abbiamo bisogno di notare un punto nello script java, è un linguaggio senza classi, tuttavia, possiamo ottenerlo usando le funzioni nello script java. Il modo più comune per raggiungere questo objective è la creazione di una funzione nello script java e l’utilizzo di una nuova parola chiave per creare un object e utilizzare questa parola chiave per definire proprietà e metodi. Di seguito è riportato 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 devi dichiarare in qualche modo la proprietà di cui hai bisogno prima di poter chiamare un metodo che passa in queste informazioni. Se non devi impostare inizialmente una proprietà, puoi semplicemente chiamare un metodo all’interno dell’object in questo modo. Probabilmente non è il modo più bello per farlo, ma funziona ancora.

 var objectA = { color: ''; callColor : function(){ console.log(this.color); } this.callColor(); } var newObject = new objectA();