"Wie funktionieren this
und $scope
in AngularJS-Controllern?"
Kurze Antwort:
this
- Wenn die Controller-Konstruktorfunktion aufgerufen wird, ist
this
der Controller.
- Wenn eine Funktion, die auf einem
$scope
-Objekt definiert ist, aufgerufen wird, ist this
das "Scope, das zum Zeitpunkt des Funktionsaufrufs wirksam war". Dies kann (oder auch nicht!) das $scope
sein, auf dem die Funktion definiert ist. Daher können this
und $scope
innerhalb der Funktion nicht dasselbe sein.
$scope
- Jeder Controller hat ein zugehöriges
$scope
-Objekt.
- Eine Controller-(Konstruktor-)Funktion ist dafür verantwortlich, Modell-Eigenschaften und Funktionen/Verhalten auf seinem zugehörigen
$scope
zu setzen.
- Nur Methoden, die auf diesem
$scope
-Objekt definiert sind (und auf Eltern-Scope-Objekten, wenn prototypische Vererbung im Spiel ist), sind vom HTML/View aus zugänglich. Z.B. von ng-click
, Filtern, etc.
Lange Antwort:
Eine Controller-Funktion ist eine JavaScript-Konstruktorfunktion. Wenn die Konstruktorfunktion ausgeführt wird (z.B. wenn eine Ansicht geladen wird), wird this
(d.h., der "Funktionskontext") auf das Controller-Objekt gesetzt. Also in der "Tabs"-Controller-Konstruktorfunktion, wenn die addPane-Funktion erstellt wird
this.addPane = function(pane) { ... }
wird sie auf dem Controller-Objekt erstellt, nicht auf dem $scope. Die Ansichten können die addPane-Funktion nicht sehen - sie haben nur Zugriff auf Funktionen, die auf $scope definiert sind. Mit anderen Worten, im HTML funktioniert dies nicht:
funktioniert nicht
Nachdem die "Tabs"-Controller-Konstruktorfunktion ausgeführt wurde, haben wir folgendes:
Die gestrichelte schwarze Linie zeigt die prototypische Vererbung an - ein isoliertes Scope erbt prototypisch von Scope. (Es erbt nicht prototypisch von dem Scope, der zum Zeitpunkt des Auftretens der Direktive im HTML wirksam war.)
Jetzt möchte die Link-Funktion der Panel-Direktive mit der Tabs-Direktive kommunizieren (was eigentlich bedeutet, dass sie das isolierte $scope der Tabs beeinflussen muss). Ereignisse könnten verwendet werden, aber ein anderer Mechanismus besteht darin, dass die Panel-Direktive den Tabs-Controller require
. (Es scheint keinen Mechanismus dafür zu geben, dass die Panel-Direktive den Tabs-$scope require
.)
Daher stellt sich die Frage: Wenn wir nur Zugriff auf den Tabs-Controller haben, wie erhalten wir Zugriff auf das isolierte Tabs-$scope (was wir wirklich wollen)?
Nun, die rote gestrichelte Linie ist die Antwort. Der "Scope" der addPane()-Funktion (hier meine ich JavaScripts Funktionsumgebung/Schlussfolgerungen) gibt der Funktion Zugriff auf das isolierte Tabs-$scope. D.h., addPane() hat Zugriff auf das "Tabs IsolateScope" im obigen Diagramm aufgrund eines Schlussfolgerung, das erstellt wurde, als addPane() definiert wurde. (Wenn wir stattdessen addPane() auf dem Tabs-$scope-Objekt definiert hätten, hätte die Panel-Direktive keinen Zugriff auf diese Funktion, und daher hätte sie keine Möglichkeit, mit dem Tabs-$scope zu kommunizieren.)
Um die andere Hälfte Ihrer Frage zu beantworten: wie funktioniert $scope in Controllern?
:
Innerhalb von auf $scope definierten Funktionen wird this
auf "das $scope, das zum Zeitpunkt des Funktionsaufrufs wirksam war" gesetzt. Angenommen, wir haben das folgende HTML:
"this" und $scope protokollieren - übergeordnetes Scope
"this" und $scope protokollieren - untergeordnetes Scope
Und das ParentCtrl
hat (ausschließlich)
$scope.logThisAndScope = function() {
console.log(this, $scope)
}
Wenn Sie auf den ersten Link klicken, wird angezeigt, dass this
und $scope
gleich sind, da "das zum Funktionsaufruf wirksame Scope" das Scope ist, das mit dem ParentCtrl
verbunden ist.
Wenn Sie auf den zweiten Link klicken, wird deutlich, dass this
und $scope
nicht gleich sind, da "das zum Funktionsaufruf wirksame Scope" das Scope ist, das mit dem ChildCtrl
verbunden ist. Hier ist also this
auf das $scope
von ChildCtrl
gesetzt. Innerhalb der Methode ist $scope
immer noch das $scope von ParentCtrl
.
Fiddle
Ich versuche, innerhalb einer auf $scope definierten Funktion nicht this
zu verwenden, da es verwirrend wird, welches $scope betroffen ist, insbesondere wenn ng-repeat, ng-include, ng-switch und Direktiven alle ihre eigenen untergeordneten Scopes erstellen können.
1 Stimmen
Ich finde das auch verwirrend. Wenn eine Ansicht einen Controller spezifiziert (z.B., ng-controller='...'), scheint der damit verbundene $scope ebenfalls mitzukommen, da die Ansicht auf $scope-Eigenschaften zugreifen kann. Aber wenn eine Direktive einen anderen Controller 'require't (und ihn dann in ihrer Linking-Funktion verwendet), kommt der damit verbundene $scope nicht mit?
0 Stimmen
Ist dieses verwirrende Zitat über "Vorherige Versionen..." mittlerweile entfernt worden? Dann wäre vielleicht ein Update angebracht?
0 Stimmen
Für Unittesting, wenn Sie 'this' anstelle von '$scope' verwenden, können Sie den Controller nicht mit einem gemockten Scope injizieren und somit keine Unittests durchführen. Ich glaube nicht, dass es eine gute Praxis ist, 'this' zu verwenden.