Ich bevorzuge die Verwendung von OOP in großen Projekten wie dem, an dem ich gerade arbeite. Ich muss mehrere Klassen in JavaScript erstellen, aber wenn ich mich nicht irre, gibt es zumindest ein paar Möglichkeiten, dies zu tun. Was wäre die Syntax und warum würde es so gemacht werden?
Ich möchte die Verwendung von Bibliotheken von Drittanbietern vermeiden - zumindest zunächst.
Auf der Suche nach anderen Antworten habe ich den Artikel Objektorientierte Programmierung mit JavaScript, Teil I: Vererbung - Doc JavaScript gefunden, der die objektorientierte Programmierung in JavaScript behandelt. Gibt es eine bessere Möglichkeit, Erbschaft zu leisten?
So gehen Sie vor, ohne externe Bibliotheken zu verwenden:
// Define a class like this
function Person(name, gender){
// Add object properties like this
this.name = name;
this.gender = gender;
}
// Add methods like this. All Person objects will be able to invoke this
Person.prototype.speak = function(){
alert("Howdy, my name is" + this.name);
};
// Instantiate new objects with 'new'
var person = new Person("Bob", "M");
// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"
Nun ist die wirkliche Antwort viel komplexer. In JavaScript gibt es beispielsweise keine Klassen. JavaScript verwendet ein prototype
-basiertes Vererbungsschema.
Darüber hinaus gibt es zahlreiche beliebte JavaScript-Bibliotheken, die ihren eigenen Stil haben, um klassenähnliche Funktionen in JavaScript anzunähern. Sie sollten mindestens Prototype und jQuery ausprobieren.
Die Entscheidung, welche davon die "Beste" ist, ist eine großartige Möglichkeit, einen heiligen Krieg gegen Stack Overflow zu beginnen. Wenn Sie sich mit einem größeren, JavaScript-schweren Projekt befassen, lohnt es sich auf jeden Fall, eine beliebte Bibliothek zu lernen und auf ihre Weise zu tun. Ich bin ein Prototyp, aber der Stack Overflow scheint sich auf jQuery zu neigen.
Soweit es nur "einen Weg gibt", ohne Abhängigkeiten von externen Bibliotheken, ist es meine Art, wie ich schrieb.
Die beste Methode zum Definieren einer Klasse in JavaScript besteht darin, keine Klasse zu definieren.
Ernst.
Es gibt verschiedene Arten der Objektorientierung. Einige davon sind:
Und wahrscheinlich andere, von denen ich nichts weiß.
JavaScript implementiert prototypbasierte OO. Beim prototypbasierten OO werden neue Objekte erstellt, indem andere Objekte kopiert werden (anstatt von einer Klassenvorlage instanziiert zu werden). Methoden leben direkt in Objekten und nicht in Klassen. Die Vererbung erfolgt per Delegierung: Wenn ein Objekt keine Methode oder Eigenschaft hat, wird es nach Prototyp (en) (d. H. Dem Objekt, aus dem es geklont wurde), den Prototypen des Prototyps usw. gesucht.
Mit anderen Worten: Es gibt keine Klassen.
JavaScript hat tatsächlich einen Nice Tweak dieses Modells: Konstruktoren. Sie können Objekte nicht nur durch Kopieren vorhandener Objekte erstellen, sondern auch sozusagen "aus der Luft" konstruieren. Wenn Sie eine Funktion mit dem Schlüsselwort new
aufrufen, wird diese Funktion zu einem Konstruktor, und das Schlüsselwort this
zeigt nicht auf das aktuelle Objekt, sondern auf ein neu erstelltes "leeres". So können Sie ein Objekt beliebig konfigurieren. Auf diese Weise können JavaScript-Konstruktoren eine der Rollen von Klassen in traditionellen, klassenbasierten OO übernehmen: Sie dienen als Vorlage oder als Entwurf für neue Objekte.
Nun ist JavaScript eine sehr mächtige Sprache, daher ist es ziemlich einfach, ein klassenbasiertes OO - System innerhalb von JavaScript zu implementieren, wenn Sie möchten. Sie sollten dies jedoch nur tun, wenn Sie wirklich einen Bedarf dafür haben, und nicht nur weil Java dies so tut.
In der ES2015-Spezifikation können Sie die Klassensyntax verwenden, die nur Zucker über dem Prototypsystem ist.
class Person {
constructor(name) {
this.name = name;
}
toString() {
return `My name is ${ this.name }.`;
}
}
class Employee extends Person {
constructor(name, hours) {
super(name);
this.hours = hours;
}
toString() {
return `${ super.toString() } I work ${ this.hours } hours.`;
}
}
Der Hauptvorteil besteht darin, dass statische Analysewerkzeuge es einfacher finden, diese Syntax anzugreifen. Es ist auch für andere, die aus klassenbasierten Sprachen kommen, einfacher, die Sprache als Polyglot zu verwenden.
Seien Sie vorsichtig bei den derzeitigen Einschränkungen. Um private Eigenschaften zu erreichen, muss auf unter Verwendung von Symbols oder WeakMaps zurückgegriffen werden. In zukünftigen Versionen werden Klassen höchstwahrscheinlich um diese fehlenden Funktionen erweitert.
Browser-Unterstützung ist im Moment nicht sehr gut (wird von fast allen außer IE unterstützt), aber Sie können diese Funktionen jetzt mit einem Transpiler wie Babel verwenden.
Ich ziehe es vor, Daniel X zu verwenden. Moores{SUPER: SYSTEM}
. Dies ist eine Disziplin, die Vorteile bietet, z. B. echte Instanzvariablen, auf Eigenschaften basierende Vererbung, Klassenhierarchien und Konfigurationsoptionen. Das folgende Beispiel veranschaulicht die Verwendung von echten Instanzvariablen, die meiner Meinung nach der größte Vorteil sind. Wenn Sie keine Instanzvariablen benötigen und nur mit öffentlichen oder privaten Variablen zufrieden sind, gibt es wahrscheinlich einfachere Systeme.
function Person(I) {
I = I || {};
Object.reverseMerge(I, {
name: "McLovin",
age: 25,
homeState: "Hawaii"
});
return {
introduce: function() {
return "Hi I'm " + I.name + " and I'm " + I.age;
}
};
}
var fogel = Person({
age: "old enough"
});
fogel.introduce(); // "Hi I'm McLovin and I'm old enough"
Wow, das ist an sich nicht wirklich sehr nützlich, aber schauen Sie sich das Hinzufügen einer Unterklasse an:
function Ninja(I) {
I = I || {};
Object.reverseMerge(I, {
belt: "black"
});
// Ninja is a subclass of person
return Object.extend(Person(I), {
greetChallenger: function() {
return "In all my " + I.age + " years as a ninja, I've never met a challenger as worthy as you...";
}
});
}
var resig = Ninja({name: "John Resig"});
resig.introduce(); // "Hi I'm John Resig and I'm 25"
Ein weiterer Vorteil ist die Fähigkeit, Vererbung auf Basis von Modulen und Merkmalen zu haben.
// The Bindable module
function Bindable() {
var eventCallbacks = {};
return {
bind: function(event, callback) {
eventCallbacks[event] = eventCallbacks[event] || [];
eventCallbacks[event].Push(callback);
},
trigger: function(event) {
var callbacks = eventCallbacks[event];
if(callbacks && callbacks.length) {
var self = this;
callbacks.forEach(function(callback) {
callback(self);
});
}
},
};
}
Ein Beispiel dafür, dass die Personenklasse das bindbare Modul enthält.
function Person(I) {
I = I || {};
Object.reverseMerge(I, {
name: "McLovin",
age: 25,
homeState: "Hawaii"
});
var self = {
introduce: function() {
return "Hi I'm " + I.name + " and I'm " + I.age;
}
};
// Including the Bindable module
Object.extend(self, Bindable());
return self;
}
var person = Person();
person.bind("eat", function() {
alert(person.introduce() + " and I'm eating!");
});
person.trigger("eat"); // Blasts the alert!
Offenlegung: Ich bin Daniel X. Moore und dies ist mein{SUPER: SYSTEM}
. Es ist der beste Weg, eine Klasse in JavaScript zu definieren.
var Animal = function(options) {
var name = options.name;
var animal = {};
animal.getName = function() {
return name;
};
var somePrivateMethod = function() {
};
return animal;
};
// usage
var cat = Animal({name: 'tiger'});
Im Folgenden werden die Möglichkeiten beschrieben, Objekte in Javascript zu erstellen, die ich bisher verwendet habe
Beispiel 1:
obj = new Object();
obj.name = 'test';
obj.sayHello = function() {
console.log('Hello '+ this.name);
}
Beispiel 2
obj = {};
obj.name = 'test';
obj.sayHello = function() {
console.log('Hello '+ this.name);
}
obj.sayHello();
Beispiel 3:
var obj = function(nameParam) {
this.name = nameParam;
}
obj.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
Beispiel 4: Tatsächlicher Nutzen von Object.create (). Bitte beziehen Sie sich auf [diesen Link]
var Obj = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var usrObj = Object.create(Obj); // <== one level of inheritance
usrObj.init('Bob');
usrObj.sayHello();
Beispiel 5 (Angepasstes Crockford Object.create):
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
Eine Klasse ist wie folgt definiert:
class Person {
constructor(strName, numAge) {
this.name = strName;
this.age = numAge;
}
toString() {
return '((Class::Person) named ' + this.name + ' & of age ' + this.age + ')';
}
}
let objPerson = new Person("Bob",33);
console.log(objPerson.toString());
Ich denke, Sie sollten Douglas Crockfords Prototypal Inheritance in JavaScript und Classical Inheritance in JavaScript lesen.
Beispiele von seiner Seite:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Bewirken? Es erlaubt Ihnen, Methoden auf elegante Weise hinzuzufügen:
function Parenizor(value) {
this.setValue(value);
}
Parenizor.method('setValue', function (value) {
this.value = value;
return this;
});
Ich empfehle auch seine Videos: Advanced JavaScript .
Weitere Videos finden Sie auf seiner Seite: http://javascript.crockford.com/ In John Reisigs Buch finden Sie viele Beispiele von Douglas Crockfors Website.
Weil ich den Fabrikplan von YUI/Crockford nicht zugeben werde und ich die Dinge gerne in sich geschlossen und erweiterbar halte, ist dies meine Variation:
function Person(params)
{
this.name = params.name || defaultnamevalue;
this.role = params.role || defaultrolevalue;
if(typeof(this.speak)=='undefined') //guarantees one time prototyping
{
Person.prototype.speak = function() {/* do whatever */};
}
}
var Robert = new Person({name:'Bob'});
wo idealerweise die Art des Tests so ähnlich ist wie bei der ersten prototypisierten Methode
Wenn Sie sich für einfach entscheiden, können Sie das "neue" Schlüsselwort vollständig vermeiden und einfach Factory-Methoden verwenden. Ich bevorzuge dies manchmal, weil ich JSON gerne zum Erstellen von Objekten benutze.
function getSomeObj(var1, var2){
var obj = {
instancevar1: var1,
instancevar2: var2,
someMethod: function(param)
{
//stuff;
}
};
return obj;
}
var myobj = getSomeObj("var1", "var2");
myobj.someMethod("bla");
Ich bin mir jedoch nicht sicher, was der Performance-Hit für große Objekte ist.
var Student = (function () {
function Student(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
this.fullname = firstname + " " + lastname;
}
Student.prototype.sayMyName = function () {
return this.fullname;
};
return Student;
}());
var user = new Student("Jane", "User");
var user_fullname = user.sayMyName();
So kompiliert TypeScript die Klasse mit dem Konstruktor zu JavaScript.
Der einfache Weg ist:
function Foo(a) {
var that=this;
function privateMethod() { .. }
// public methods
that.add = function(b) {
return a + b;
};
that.avg = function(b) {
return that.add(b) / 2; // calling another public method
};
}
var x = new Foo(10);
alert(x.add(2)); // 12
alert(x.avg(20)); // 15
Der Grund für that
ist, dass this
an etwas anderes gebunden werden kann, wenn Sie eine Methode als Ereignishandler angeben. Sie speichern den Wert während der Instantiierung und verwenden ihn später.
Edit: Es ist definitiv nicht der beste Weg, nur ein einfacher Weg. Ich warte auch auf gute Antworten!
Sie möchten wahrscheinlich einen Typ mithilfe des Faltmusters erstellen:
// Here is the constructor section.
var myType = function () {
var N = {}, // Enclosed (private) members are here.
X = this; // Exposed (public) members are here.
(function ENCLOSED_FIELDS() {
N.toggle = false;
N.text = '';
}());
(function EXPOSED_FIELDS() {
X.count = 0;
X.numbers = [1, 2, 3];
}());
// The properties below have access to the enclosed fields.
// Careful with functions exposed within the closure of the
// constructor, each new instance will have it's own copy.
(function EXPOSED_PROPERTIES_WITHIN_CONSTRUCTOR() {
Object.defineProperty(X, 'toggle', {
get: function () {
var before = N.toggle;
N.toggle = !N.toggle;
return before;
}
});
Object.defineProperty(X, 'text', {
get: function () {
return N.text;
},
set: function (value) {
N.text = value;
}
});
}());
};
// Here is the prototype section.
(function PROTOTYPE() {
var P = myType.prototype;
(function EXPOSED_PROPERTIES_WITHIN_PROTOTYPE() {
Object.defineProperty(P, 'numberLength', {
get: function () {
return this.numbers.length;
}
});
}());
(function EXPOSED_METHODS() {
P.incrementNumbersByCount = function () {
var i;
for (i = 0; i < this.numbers.length; i++) {
this.numbers[i] += this.count;
}
};
P.Tweak = function () {
if (this.toggle) {
this.count++;
}
this.text = 'tweaked';
};
}());
}());
Dieser Code gibt Ihnen einen Typ namens myType. Es wird interne private Felder haben, die toggle und text heißen. Es wird auch diese exponierten Mitglieder haben: die Felder count und numbers; die Eigenschaften toggle, text und numberLength; die Methoden incrementNumbersByCount und Tweak.
Das Faltmuster ist hier ausführlich beschrieben: Javascript Faltmuster
Code golf für @ liammclennans Antwort .
var Animal = function (args) {
return {
name: args.name,
getName: function () {
return this.name; // member access
},
callGetName: function () {
return this.getName(); // method call
}
};
};
var cat = Animal({ name: 'tiger' });
console.log(cat.callGetName());
Objektbasierte Klassen mit Vererbung
var baseObject =
{
// Replication / Constructor function
new : function(){
return Object.create(this);
},
aProperty : null,
aMethod : function(param){
alert("Heres your " + param + "!");
},
}
newObject = baseObject.new();
newObject.aProperty = "Hello";
anotherObject = Object.create(baseObject);
anotherObject.aProperty = "There";
console.log(newObject.aProperty) // "Hello"
console.log(anotherObject.aProperty) // "There"
console.log(baseObject.aProperty) // null
Einfach, süß und fertig.
Eine Basis
function Base(kind) {
this.kind = kind;
}
Eine Klasse
// Shared var
var _greeting;
(function _init() {
Class.prototype = new Base();
Class.prototype.constructor = Class;
Class.prototype.log = function() { _log.apply(this, arguments); }
_greeting = "Good afternoon!";
})();
function Class(name, kind) {
Base.call(this, kind);
this.name = name;
}
// Shared function
function _log() {
console.log(_greeting + " Me name is " + this.name + " and I'm a " + this.kind);
}
Aktion
var c = new Class("Joe", "Object");
c.log(); // "Good afternoon! Me name is Joe and I'm a Object"
Am Beispiel von Triptychon könnte dies noch einfacher sein:
// Define a class and instantiate it
var ThePerson = new function Person(name, gender) {
// Add class data members
this.name = name;
this.gender = gender;
// Add class methods
this.hello = function () { alert('Hello, this is ' + this.name); }
}("Bob", "M"); // this instantiates the 'new' object
// Use the object
ThePerson.hello(); // alerts "Hello, this is Bob"
Dadurch wird nur eine einzelne Objektinstanz erstellt. Dies ist jedoch immer noch hilfreich, wenn Sie mehrere Namen für Variablen und Methoden in einer Klasse einkapseln möchten. Normalerweise würde der Konstruktor keine "Bob, M" -Argumente enthalten, z. B. wenn die Methoden Aufrufe an ein System mit eigenen Daten wären, beispielsweise eine Datenbank oder ein Netzwerk.
Ich bin bei JS noch zu neu, um zu sehen, warum dies nicht die Sache prototype
verwendet.
//new way using this and new
function Persons(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
}
var gee=new Persons("gee");
gee.greeting();
var gray=new Persons("gray");
gray.greeting();
//old way
function createPerson(name){
var obj={};
obj.name=name;
obj.greeting = function(){
console.log("hello I am"+obj.name);
};
return obj;
}
var gita=createPerson('Gita');
gita.greeting();
JavaScript ist objektorientiert , aber es unterscheidet sich grundlegend von anderen OOP Sprachen wie Java, C # oder C++. Versuchen Sie nicht, es so zu verstehen. Werfen Sie das alte Wissen raus und beginnen Sie von vorne. JavaScript braucht ein anderes Denken.
Ich würde vorschlagen, ein gutes Handbuch oder etwas zu diesem Thema zu bekommen. Ich selbst habe ExtJS Tutorials das Beste für mich gefunden, obwohl ich das Framework vorher oder nach dem Lesen nicht verwendet habe. Aber es gibt eine gute Erklärung dafür, was in der JavaScript-Welt ist. Sorry, es scheint, dass der Inhalt entfernt wurde. Hier ist ein Link zu archive.org copy stattdessen. Funktioniert heute. : P