Warum dieser Schnipsel folgende Zuordnung macht?
that.method = method
Welchen Zweck erfüllt method
? Wie ist es initialisiert?
Es wird als eine Variable ein paar Zeilen weiter oben initialisiert:
method = function() { ... }
Dann wird die Linie, die Sie zitiert haben, ist der Wert dieser Variablen zugewiesen wird (ein Verweis auf die Funktion) auf eine Eigenschaft auf das Objekt that
bezieht sich auf, so dass es als "Methode" des Objekts verwendet werden kann.So könnten Sie dies tun:
var x = constructor(42);
x.method(); // <== Here's where we use the function assigned to the property as a method
Mehr (auf meinem Blog): Mythical methods
Was ist der Zweck Objekte auf diese Weise zu erklären?
Crockford mag die Konstruktorfunktionen von JavaScript nicht und verwendet sie daher auch nicht. Also macht er das stattdessen. Einer der wirklich tollen Dinge über JavaScript ist, wie flexibel es ist. Sie können es als eine fast rein funktionale Sprache verwenden, Sie können es als eine prototypische Sprache verwenden, und Sie können es sogar eine Los wie eine klassenbasierte Sprache verwenden, obwohl es nicht klassenbasiert ist, weil es prototypische Features geben Sie fast alles, was Sie dafür brauchen (wie von ES6, es wird alles notwendig, um in einer klassenbasierten Weise verwendet werden, wenn man will). Und Sie können diese Ansätze kombinieren, wann immer Sie es für angebracht halten. Es ist nur so flexibel.
Im Gegensatz zu Crockford, mag ich Konstruktor Funktionen und die new
Schlüsselwort. Aber ich auch wirklich wie nicht, sie zu verwenden, wenn sie nicht das richtige Werkzeug sind, die sie häufig nicht sind.
Re Sie Ihren Kommentar unten:
Möchten Sie zufällig in der Lage ein Beispiel für Crockford Konstruktorfunktion Schnipsel in der tatsächlichen Verwendung zur Verfügung zu stellen? Wird diese Methode verwendet, um dieses Mitglied zu initialisieren, oder bin ich hier völlig ausgeschaltet?
Es gibt keine that.member
. member
in dem Code, den Sie zeigten, ist keine Eigenschaft des Objekts, es ist nur eine Variable. Die method
-Funktion, die innerhalb des Aufrufs von constructor
erstellt wird, hat Zugriff auf diese Variable, weil es eine Schließung über den Kontext des Aufrufs an constructor
ist, aber nichts, das nur Zugriff auf das zurückgegebene Objekt hat, kann member
sehen. So member
ist wirklich private zu den Funktionen innerhalb constructor
erstellt. Zwei weitere Artikel, die hier nützlich sein können: Closures are not complicated von meinem Blog, der erklärt, was eine "Schließung" ist, und Crockfords Private Members in JavaScript, die beschreibt, wie private Informationen mit Objekten verknüpft sind, die er in dem von Ihnen zitierten Beispiel verwendet. (Ich schon erwähnt, eine andere Art und Weise auf Objekte am Ende dieser Antwort private Informationen zu haben.)
Was das Beispiel, das Sie zitiert haben tut demonstriert zwei weitgehend unabhängige Dinge:
Ein Mittel zum Augmented Erzeugen (nicht abgeleitet) Objekte
A mittels
Die patte mit diesen Objekten zugeordnet wirklich private Informationen mit er zeigt, ist nicht der einzige Weg, um diese Dinge zu tun, aber das ist es, was es zeigt.
Re ein konkretes Beispiel:
Lassen Sie uns sagen, dass wir „Ding“ Objekte erstellen möchten. Es spielt keine Rolle, was sie sind, aber sie haben eine Eigenschaft namens "name" (die nicht privat sein muss). (Sie würden wahrscheinlich auch Methoden, aber die sind nicht wichtig, so werden wir sie der Kürze halber auslassen und Klarheit.) Also würden wir mit so etwas wie dies starten:
// Very simple Crockford-style constructor
function createThing(name) {
return {name: name}; // Again, there'd probably be more to it, this is simple on purpose
}
// Usage
var t = createThing("foo");
console.log(t.name); // "foo"
So weit so gut. Nun wollen wir auch haben die Fähigkeit, Dinge zu erstellen, denen wir einen Zähler hinzufügen können, und eine Methode, die das Ding "verwendet" und zählt, dass verwenden, die neue Anzahl der Verwendungen zurückgibt. (Ja, das ist ein konstruiertes Beispiel.) Eine naive Version, wieder so etwas wie Crockford Art und Weise mit, dies zu tun, könnte wie folgt aussehen:
// Naive approach
function createThingWithCounter(name) {
var that = createThing(name);
that.useCounter = 0;
that.use = function() {
// ...do something with `that`...
// Return the new number of times we've "used" the thing
return ++that.useCounter;
};
return that;
}
// Usage
var t = createThingWithCounter("foo");
console.log(t.name); // "foo"
console.log(t.use()); // 1
console.log(t.use()); // 2
wieder so weit, so gut. Aber das Problem ist, useCounter
ist eine öffentliche Eigenschaft auf dem Objekt. So können wir Durcheinander über mit ihm von außerhalb des createThingWithCounter
Code:
var t = createThingWithCounter("foo");
console.log(t.name); // "foo"
console.log(t.use()); // 1
t.useCounter = 0;
console.log(t.use()); // 1 -- uh oh!
Wir wollen nicht useCounter
Öffentlichkeit. Nun gibt es verschiedene Ansätze, um es privat zu machen, einschließlich der Tatsache, dass es nicht nur privat ist, sondern eine Benennungskonvention verwendet (typischerweise beginnt es mit einem Unterstrich, zB _useCounter
) bedeutet "lass das alleine oder sonst!", Aber das Muster wir sind Betrachten lässt uns machen useCounter
wirklich privat durch Nutzung der Tatsache, dass die use
Methode ist eine Schließung über den Kontext des Aufrufs an createThingWithCounter
. Das, plus ein wenig die Quelle der Neuanordnung besser die zitierte Muster passen, gibt uns dies:
function createThingWithCounter(name) {
var that = createThing(name),
useCounter = 0,
use = function() {
// ...do something with `that`...
// Return the new number of times we've "used" the thing
return ++useCounter;
};
that.use = use;
return that;
}
Nun useCounter
gar kein Eigentum an dem Objekt ist. Es ist wirklich privat, nichts außerhalb von createThingWithCounter
kann es sehen oder ändern:
var t = createThingWithCounter("foo");
console.log(t.name); // "foo"
console.log(t.use()); // 1
t.useCounter = 0; // <== Has absolutely no effect on the real counter
console.log(t.use()); // 2
Damit unser Beton ist (wenn erfundene) Beispiel. Hier ist, wie es Karten zum angezeigten Muster:
constructor
= createThingWithCounter
otherConstructor
= createThing
member
= useCounter
method
= use
Nun, ich will e mphasize, dass es oben nichts gibt, was Sie mit normalen Konstruktorfunktionen unter Verwendung von new
nicht tun können. Es sieht nicht einmal so anders aus:
Sie sind nur verschiedene Möglichkeiten, ähnliche Ziele zu erreichen.
Es gibt auch einen anderen Weg: Ableitung, anstatt Augmentation.Und wie bei der Augmentation kann die Ableitung im Crockford-Stil oder über Standardkonstruktorfunktionen erfolgen. Es ist wieder diese wunderbare Flexibilität der Sprache. :-)
Eine letzte Anmerkung über private Informationen: In beiden Stilen der oben genannten ist die useCounter
wirklich privat, aber es ist keine Eigenschaft des Objekts. Es ist überhaupt nicht auf dem Objekt. Und es gibt ein paar Kosten, die damit verbunden sind, wie wir diese Privatsphäre bekommen: Zuerst müssen wir eine use
Funktion für jede Instanz erstellen. Diese Funktionen werden nicht zwischen Instanzen aufgeteilt, wie Funktionen, die an Prototypen (und verschiedene andere Arten) angebracht sind. Die Kosten dort sind 2014 ziemlich gering, moderne Motoren sind ziemlich schlau daran, das zu optimieren; es wäre viel teurer gewesen, 15 Jahre oder so zurück.
Die anderen Kosten sind, dass die use
-Funktion nicht an anderer Stelle wiederverwendet werden kann, was sie mit der überwiegenden Mehrheit der Funktionen in JavaScript in Widerspruch setzt. Wenn man sich the spec betrachten, sehen Sie diese Sprache auf fast jedem vordefinierten JavaScript-Methode:
HINWEIS: Die xyz Funktion absichtlich allgemein ist; es erfordert nicht, dass sein dieser Wert ein Whatsit-Objekt ist. Daher kann es auf andere Arten von Objekten zur Verwendung als eine Methode übertragen werden.
Also, wenn ich etwas haben, dass viele wie ein Array ist, ist aber kein Array (wie das JavaScript arguments
Objekt) kann ich Methoden von Array.prototype
auf sie setzen und, sofern mein Objekt ist Array-artiges genug, werden sie gut funktionieren:
var arrayLikeObject = {
length: 2,
0: "one",
1: "two",
indexOf: Array.prototype.indexOf
};
console.log(arrayLikeObject.indexOf("two")); // 1
Unsere use
Verfahren nicht auf diese Weise wiederverwendet werden können. Es ist an die "Sache mit Zähler" -Instanz gebunden, auf die es sich bezieht. Wenn wir tat versuchen, es auf diese Weise zu verwenden, würden wir mit seltsamen Übersprechen zwischen dem Objekt, das wir es auf die ursprüngliche "Sache mit Counter" -Objekt, aus dem wir es genommen haben, enden würde. Seltsames Übersprechen dieser Art ist eine großartige Weise, wirklich unangenehme, zeitraubende, peinliche Fehler in Projekten jeder Größe zu haben. Die nächste Version des JavaScript-Standards ECMAScript6 gibt uns die Möglichkeit, private Eigenschaften zu haben. Das heißt, tatsächliche Eigenschaften von Objekten, die privat sind (oder so privat wie Informationen in modernen Sprachen/Umgebungen). Da die Eigenschaften tatsächlich Eigenschaften des Objekts sind, müssen wir uns nicht darauf verlassen, dass die use
-Funktion eine Schließung ist, und wir können sie für ein Prototypobjekt definieren und/oder für andere Objekte wiederverwenden die oben genannten Kosten gelten.
Und noch besser, das ziemlich clevere Muster, das sie verwenden, um diese Funktion hinzuzufügen, kann jetzt verwendet werden, um ~ 90% der Vorteile zu erhalten, die es bietet. Also, wenn das ein Thema ist, das dich interessiert, ein letzter Blogpost für dich: Private properties in ES6 -- and ES3, and ES5.
Haben Sie einen Link dazu? Ich frage mich, ob endlich etwas veröffentlicht wird, wo er Konstruktorfunktionen und das neue Schlüsselwort korrekt implementiert. Wenn ich es so benutzen würde, wie ich es tue, gehe ich wahrscheinlich auch aus dem Weg, um es zu vermeiden. Der "korrekte" Weg, Konstruktorfunktionen zu benutzen, wird hier erklärt: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 andere Muster zum Erstellen von Objektinstanzen können ihre Verwendung haben (außer Verwirrung Programmierer, die Ihren Code beibehalten) und tut dies auch mit neuen – HMR
diese ganze Funktion ist analog zu einem "Klasse" -Konstruktor. "other_constructor" ist ein Basisklassenkonstruktor. "Mitglied" ist eine private Mitgliedsvariable. "Methode" ist eine öffentliche oder private Methode. Die Zeile 'that.method = method' wandelt sie effektiv von einer privaten Methode in eine öffentliche Methode um, da sie nun öffentlich als Eigenschaft des zurückgegebenen Objekts verfügbar ist. andernfalls würde es wie "Mitglied" als Teil der Schließung privat bleiben. –