Können JavaScript-Klassen / -Objekte Konstruktoren haben? Wie entstehen sie?
Können JavaScript-Klassen / -Objekte Konstruktoren haben? Wie entstehen sie?
Antworten:
Prototypen verwenden:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
"Farbe" ausblenden (ähnelt etwas einer privaten Mitgliedsvariablen):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Verwendungszweck:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
color
. Ich würde vorschlagen, welche Sie verwenden, hängt weitgehend von
var
macht eine private Variable. this
macht eine öffentliche Variable
Foo
, während er im letzteren Fall weiß, dass Foo
er aufgerufen wird. Sehr hilfreich beim Debuggen.
Hier ist eine Vorlage, die ich manchmal für OOP-ähnliches Verhalten in JavaScript verwende. Wie Sie sehen können, können Sie private (sowohl statische als auch Instanz-) Mitglieder mithilfe von Closures simulieren. Was zurückgegeben new MyClass()
wird, ist ein Objekt mit nur den Eigenschaften, die dem this
Objekt und im prototype
Objekt der "Klasse" zugewiesen sind .
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;
})();
Ich wurde nach der Vererbung anhand dieses Musters gefragt.
// 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;
})();
Und ein Beispiel, um alles zu nutzen:
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
Wie Sie sehen können, interagieren die Klassen korrekt miteinander (sie teilen die statische ID von MyClass
, die announce
Methode verwendet die richtige get_name
Methode usw.)
Eine Sache zu beachten ist die Notwendigkeit, Instanzeigenschaften zu beschatten. Sie können die inherit
Funktion tatsächlich alle Instanzeigenschaften (mit hasOwnProperty
) durchlaufen lassen, die Funktionen sind, und automatisch eine super_<method name>
Eigenschaft hinzufügen . Auf diese Weise können Sie aufrufen, this.super_get_name()
anstatt es in einem temporären Wert zu speichern und es gebunden mit aufzurufen call
.
Bei Methoden für den Prototyp müssen Sie sich jedoch nicht um die oben genannten Punkte kümmern. Wenn Sie auf die Prototypmethoden der Superklasse zugreifen möchten, können Sie einfach aufrufen this.constructor.super.prototype.methodName
. Wenn Sie es weniger ausführlich gestalten möchten, können Sie natürlich praktische Eigenschaften hinzufügen. :) :)
cls.prototype
Teil: "Instanzenübergreifend geteilt" dient nur zum Lesen des Werts (Aufruf announce
). Wenn Sie einen myClassInstance.announce
anderen Wert festlegen , wird eine neue Eigenschaft in erstellt myClassInstance
, sodass dies nur für dieses Objekt gilt, nicht für andere Instanzen der Klasse. Das Zuweisen zu wirkt sich MyClass.prototype.announce
jedoch auf alle Instanzen aus.
MyClass.get_nextId()
Es scheint mir, dass die meisten von Ihnen ein Beispiel für Getter und Setter geben, die kein Konstruktor sind (dh http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .
Mittagessen-Dan war näher, aber das Beispiel funktionierte nicht in jsFiddle.
In diesem Beispiel wird eine private Konstruktorfunktion erstellt, die nur während der Erstellung des Objekts ausgeführt wird.
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
Wenn Sie öffentliche Eigenschaften zuweisen möchten, kann der Konstruktor wie folgt definiert werden:
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()
Funktion handelt :). Dieses Beispiel sowie Beispiele in den anderen Antworten können jedoch leicht erweitert werden, um Parameter zu akzeptieren.
Box
Funktion und Sie können loslegen (es ist immer noch "privat"). "Privat" in Javascript bedeutet nur, über den lexikalischen Bereich zugänglich zu sein. Keine Notwendigkeit, Mitgliedern zuzuweisen. Zusätzlich: Dieser Code ist falsch. Es wird eine globale __construct
Variable erstellt, was ziemlich schlecht ist. var
sollte verwendet werden, um den Umfang von einzuschränken __construct
.
Was ist der Sinn der "Konstruktor" -Eigenschaft? Sie können nicht herausfinden, wo es nützlich sein könnte, irgendwelche Ideen?
Der Zweck der Konstruktoreigenschaft besteht darin, eine Möglichkeit bereitzustellen, so zu tun, als ob JavaScript Klassen hat. Sie können den Konstruktor eines Objekts nach seiner Erstellung nicht sinnvoll ändern. Es ist kompliziert.
Ich habe vor einigen Jahren ein ziemlich umfassendes Stück darüber geschrieben: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Beispiel hier: http://jsfiddle.net/FZ5nC/
Probieren Sie diese Vorlage aus:
<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>
Sie müssen Ihren Namespace anpassen, wenn Sie eine statische Klasse definieren:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Beispielklasse:
<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>
Beispielinstanziierung:
<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>
Hinweisfunktionen sind definiert als AB = Funktion A_B (). Dies soll das Debuggen Ihres Skripts erleichtern. Öffnen Sie das Inspect Element-Bedienfeld von Chrome, führen Sie dieses Skript aus und erweitern Sie den Debug-Backtrace:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
Dies ist ein Konstruktor:
function MyClass() {}
Wenn Sie das tun
var myObj = new MyClass();
MyClass
wird ausgeführt und ein neues Objekt dieser Klasse zurückgegeben.
alert(valuePassedInAsArgument);
, dass dies ganz oben in Ihrer Klasse steht. Dies wird für jede Instanziierung einmal ausgeführt, sodass die gesamte Klasse der Konstruktor selbst ist.
new object is returned of that class
- Ist es nicht eher so, als würde ein neues Objekt dieser Funktion zurückgegeben?
Ich fand dieses Tutorial sehr nützlich. Dieser Ansatz wird von den meisten jQuery-Plug-Ins verwendet.
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;
};
Jetzt ,
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
Dieses Muster hat mir gut gedient. Mit diesem Muster erstellen Sie Klassen in separaten Dateien und laden sie "nach Bedarf" in Ihre gesamte App.
// 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
im Konstruktor (oder Funktionsargument oder in einer konstruktorähnlichen Funktion).
Ja, Sie können einen Konstruktor in einer Klassendeklaration wie folgt definieren:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Ich werde wohl posten, was ich mit dem Schließen von Javascript mache, da noch niemand das Schließen verwendet.
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);
}
};
};
Kommentare und Vorschläge zu dieser Lösung sind willkommen. :) :)
Mit dem obigen Beispiel von Nick können Sie einen Konstruktor für Objekte ohne Parameter erstellen, indem Sie eine return-Anweisung als letzte Anweisung in Ihrer Objektdefinition verwenden. Geben Sie Ihre Konstruktorfunktion wie folgt zurück, und der Code wird bei jeder Erstellung des Objekts in __construct ausgeführt:
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();
in der obigen Zeile zu verwenden, wird alert("Object Created.");
nichts alarmiert. Es wird ein Fehler wie "getColor ist nicht definiert" angezeigt. Wenn Sie möchten, dass das Konstrukt andere Methoden im Objekt aufrufen kann, muss es nach allen anderen Methoden definiert werden. Anstatt also __construct();
die letzte Zeile aufzurufen, definieren Sie einfach das Konstrukt dort unten und setzen ()
Sie es nach, um die automatische Ausführung zu erzwingen.
()
am Ende der __construct-Definition führte immer noch zu dem Fehler. Ich musste __construct();
wie im Originalcode in einer eigenen Leitung anrufen , um den Fehler zu vermeiden.
Vielleicht ist es etwas einfacher geworden, aber im Folgenden habe ich mir 2017 Folgendes ausgedacht:
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;
}
}
Bei Verwendung der obigen Klasse habe ich Folgendes:
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());
Wie Sie sehen können, akzeptiert der Konstruktor zwei Parameter, und wir legen die Eigenschaften des Objekts fest. Wir ändern auch die Farbe und Form des Objekts mithilfe der setter
Funktionen und beweisen, dass seine Änderung beim Aufruf getInfo()
nach diesen Änderungen erhalten blieb.
Ein bisschen spät, aber ich hoffe das hilft. Ich habe dies mit einem mocha
Unit-Test getestet und es funktioniert gut.
Sie tun dies, wenn Sie Typescript verwenden - Open Source von MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Mit Typescript können Sie OO-Konstrukte "fälschen", die zu Javascript-Konstrukten kompiliert werden. Wenn Sie ein großes Projekt starten, sparen Sie möglicherweise viel Zeit und haben gerade die Version 1.0 erreicht.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
Der obige Code wird kompiliert zu:
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
In JavaScript definiert der Aufruftyp das Verhalten der Funktion:
func()
obj.func()
new func()
func.call()
oderfunc.apply()
Die Funktion wird beim Aufruf mit dem Operator als Konstruktor aufgerufen new
:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Jede Instanz oder jedes Prototypobjekt in JavaScript verfügt über eine Eigenschaft constructor
, die auf die Konstruktorfunktion verweist.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Überprüfen Sie diesen Beitrag über die Konstruktoreigenschaft.
Während ich die großartige Vorlage von Blixt von oben verwendete, stellte ich fest, dass sie mit der mehrstufigen Vererbung (MyGrandChildClass, die MyChildClass erweitert, um MyClass zu erweitern) nicht gut funktioniert. Der Aufruf des Konstruktors des ersten Elternteils erfolgt immer wieder. Hier ist eine einfache Problemumgehung: Wenn Sie eine mehrstufige Vererbung benötigen, anstatt die this.constructor.super.call(this, surName);
Verwendung chainSuper(this).call(this, surName);
mit der wie folgt definierten Kettenfunktion zu verwenden:
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/ ist ziemlich gut für oop in Js. Wenn Sie private, geschützte, öffentliche Variablen und Funktionen sowie Vererbungsfunktionen bereitstellen. Beispielcode:
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
nur um etwas Abwechslung zu bieten. ds.oop ist eine gute Möglichkeit, Klassen mit Konstruktoren in Javascript zu deklarieren. Es unterstützt jede mögliche Art der Vererbung (einschließlich eines Typs, den selbst c # nicht unterstützt) sowie Schnittstellen, was sehr hilfreich ist.
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
Hier müssen wir einen Punkt im Java-Skript beachten, es ist eine klassenlose Sprache, aber wir können es erreichen, indem wir Funktionen im Java-Skript verwenden. Der häufigste Weg, um dies zu erreichen, besteht darin, eine Funktion im Java-Skript zu erstellen und ein neues Schlüsselwort zum Erstellen eines Objekts zu verwenden und dieses Schlüsselwort zum Definieren von Eigenschaften und Methoden zu verwenden. Unten sehen Sie das Beispiel.
// 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
In den meisten Fällen müssen Sie die benötigte Eigenschaft irgendwie deklarieren, bevor Sie eine Methode aufrufen können, die diese Informationen übergibt. Wenn Sie zunächst keine Eigenschaft festlegen müssen, können Sie einfach eine Methode innerhalb des Objekts wie folgt aufrufen. Wahrscheinlich nicht die schönste Art, dies zu tun, aber das funktioniert immer noch.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();