Frage 'this' vs $ scope in AngularJS-Controllern


In dem Bereich "Create Components" auf der Homepage von AngularJS, es gibt dieses Beispiel:

controller: function($scope, $element) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
    angular.forEach(panes, function(pane) {
      pane.selected = false;
    });
    pane.selected = true;
  }
  this.addPane = function(pane) {
    if (panes.length == 0) $scope.select(pane);
    panes.push(pane);
  }
}

Beachten Sie, wie die select Methode wird hinzugefügt $scope, aber die addPane Methode wird hinzugefügt this. Wenn ich es zu ändern $scope.addPane, der Code bricht.

Die Dokumentation besagt, dass es tatsächlich einen Unterschied gibt, aber nicht erwähnt, was der Unterschied ist:

Frühere Versionen von Angular (vor 1.0 RC) haben Sie verwenden können this austauschbar mit der $scope Methode, aber das ist nicht mehr der Fall. Innerhalb von Methoden, die im Bereich definiert sind this und $scope sind austauschbar (Winkelsets this zu $scope), aber nicht in Ihrem Controller-Konstruktor.

Wie geht es? this und $scope Arbeit in AngularJS Controllern?


965
2017-07-23 02:55


Ursprung


Antworten:


"Wie geht es? this und $scope Arbeit in AngularJS-Controllern? "

Kurze Antwort:

  • this
    • Wenn die Controller-Konstruktor-Funktion aufgerufen wird, this ist der Controller.
    • Wenn eine Funktion auf a definiert ist $scope Objekt heißt, this ist der "Gültigkeitsbereich, wenn die Funktion aufgerufen wurde". Dies kann (oder darf nicht!) Das sein $scope dass die Funktion definiert ist. Also, in der Funktion, this und $scope kann nicht sei gleich.
  • $scope
    • Jeder Controller hat eine Verbindung $scope Objekt.
    • Eine Controller- (Konstruktor) -Funktion ist verantwortlich für das Festlegen von Modelleigenschaften und Funktionen / Verhalten auf dem zugehörigen Element $scope.
    • Es sind nur Methoden definiert $scope Objekt (und Objekte des übergeordneten Bereichs, wenn eine prototypische Vererbung im Spiel ist) können über die HTML / View aufgerufen werden. Zum Beispiel von ng-click, Filter usw.

Lange Antwort:

Eine Controller-Funktion ist eine JavaScript-Konstruktorfunktion. Wenn die Konstruktorfunktion ausgeführt wird (z. B. wenn eine Ansicht geladen wird), this (d. h. der "Funktionskontext") wird auf das Controllerobjekt gesetzt. Also in der Controller-Konstruktor-Funktion "tabs", wenn die addPane-Funktion erstellt wird

this.addPane = function(pane) { ... }

Es wird auf dem Controller-Objekt erstellt, nicht auf $ scope. Ansichten können die Funktion addPane nicht sehen - sie haben nur Zugriff auf Funktionen, die in $ scope definiert sind. Mit anderen Worten, im HTML funktioniert das nicht:

<a ng-click="addPane(newPane)">won't work</a>

Nachdem die Steuerungskonstruktorfunktion "Tabs" ausgeführt wurde, haben wir Folgendes:

after tabs controller constructor function

Die gestrichelte schwarze Linie zeigt die prototypische Vererbung an - ein isolierter Bereich, von dem prototypisch erbt wird Umfang. (Es wird nicht prototypisch von dem Gültigkeitsbereich übernommen, in dem die Anweisung im HTML-Code gefunden wurde.)

Nun möchte die Link-Funktion der Fenster-Direktive mit der Tabs-Direktive kommunizieren (was wirklich bedeutet, dass sie die Tabs beeinflussen muss, isoliere $ scope in irgendeiner Weise). Es könnten Ereignisse verwendet werden, aber ein anderer Mechanismus besteht darin, die Fensteranweisung zu haben require der Tabulator-Controller. (Es scheint keinen Mechanismus für die Fensteranweisung zu geben require die Tabs $ scope.)

Also, das wirft die Frage auf: Wenn wir nur Zugriff auf den Tabs-Controller haben, wie erhalten wir Zugriff auf die Tabs isolieren $ scope (was ist das, was wir wirklich wollen)?

Nun, die rote gepunktete Linie ist die Antwort. Der "Bereich" der AddPane () - Funktion (ich verweise hier auf den Funktionsumfang / Schließungen von JavaScript) gibt der Funktion Zugriff auf die Tabs isolate $ scope. Das heißt, addPane () hat Zugriff auf die "Registerkarten IsolateScope" im obigen Diagramm wegen einer Schließung, die erstellt wurde, als addPane () definiert wurde. (Wenn wir stattdessen addPane () auf den Registern $ scope object definieren würden, hätte die Fensteranweisung keinen Zugriff auf diese Funktion und hätte daher keine Möglichkeit, mit den Registerkarten $ scope zu kommunizieren.)

Um den anderen Teil Ihrer Frage zu beantworten: how does $scope work in controllers?:

Innerhalb von Funktionen, die in $ scope definiert sind, this wird auf "der $ scope in effect wo / wann die Funktion aufgerufen wurde" gesetzt. Angenommen, wir haben den folgenden HTML-Code:

<div ng-controller="ParentCtrl">
   <a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
   <div ng-controller="ChildCtrl">
      <a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
   </div>
</div>

Und das ParentCtrl (Allein) hat

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

Wenn Sie auf den ersten Link klicken, wird dies angezeigt this und $scope sind gleich, seit "der Gültigkeitsbereich, als die Funktion aufgerufen wurde"ist der Umfang mit dem verbunden ParentCtrl.

Durch Klicken auf den zweiten Link wird angezeigt this und $scope sind nicht das gleiche, seit "der Gültigkeitsbereich, als die Funktion aufgerufen wurde"ist der Umfang mit dem verbunden ChildCtrl. Also hier, this ist eingestellt auf ChildCtrlist es $scope. Innerhalb der Methode $scope ist immer noch der ParentCtrl's $ Umfang.

Geige

Ich versuche nicht zu benutzen this innerhalb einer in $ scope definierten Funktion, da es verwirrend wird, welcher $ scope betroffen ist, insbesondere wenn man bedenkt, dass ng-repeat, ng-include, ng-switch und directions alle ihre eigenen untergeordneten Bereiche erstellen können.


949
2018-01-05 04:48



Der Grund, dem 'addPane' zugewiesen wurde, ist wegen der <pane> Richtlinie.

Das pane Richtlinie tut require: '^tabs', die das Tabs-Controller-Objekt aus einer übergeordneten Direktive in die Link-Funktion einfügt.

addPane ist zugeordnet this so, dass die pane Link-Funktion kann es sehen. Dann in der pane Verknüpfungsfunktion, addPane ist nur eine Eigenschaft der tabs Controller, und es ist nur tabsControllerObject.addPane. Die Verknüpfungsfunktion der Fensterrichtlinie kann also auf das Tabs-Controller-Objekt zugreifen und somit auf die addPane-Methode zugreifen.

Ich hoffe, meine Erklärung ist klar genug. Es ist schwer zu erklären.


50
2017-07-23 15:20



Ich lese gerade eine ziemlich interessante Erklärung über den Unterschied zwischen den beiden und eine wachsende Präferenz, Modelle an den Controller anzuhängen und den Controller zu aliasieren, um Modelle an die Ansicht zu binden. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ ist der Artikel. Er erwähnt es nicht, aber wenn Sie Anweisungen definieren, wenn Sie etwas zwischen mehreren Direktiven teilen müssen und keinen Dienst möchten (es gibt legitime Fälle, in denen Dienste mühsam sind), hängen Sie die Daten an den Controller der übergeordneten Richtlinie an. Der $ scope-Dienst bietet viele nützliche Dinge, wobei $ watch am offensichtlichsten ist, aber wenn Sie nur Daten an die Ansicht binden müssen, ist die Verwendung des einfachen Controllers und des 'Controllers als' in der Vorlage in Ordnung und wohl vorzuziehen.


26
2017-08-28 21:25



In diesem Kurs(https://www.codeschool.com/courses/shaping-up-with-angular-js) Sie erklären, wie man "dieses" und viele andere Sachen benutzt.

Wenn Sie dem Controller über die Methode "this" eine Methode hinzufügen, müssen Sie diese in der Ansicht mit dem Controller-Namen "dot" Ihre Eigenschaft oder Methode aufrufen.

Wenn Sie beispielsweise Ihren Controller in der Ansicht verwenden, haben Sie möglicherweise folgenden Code:

    <div data-ng-controller="YourController as aliasOfYourController">

       Your first pane is {{aliasOfYourController.panes[0]}}

    </div>

15
2017-09-24 07:29



Ich empfehle Ihnen, den folgenden Beitrag zu lesen: http://codetunnel.io/angularjs-controller-as-oder-scope/

Es beschreibt sehr gut die Vorteile der Verwendung von "Controller as", um Variablen gegenüber "$ scope" offenzulegen.

Ich weiß, dass Sie speziell nach Methoden und nicht nach Variablen gefragt haben, aber ich denke, dass es besser ist, sich an eine Technik zu halten und konsistent zu sein.

Also, meiner Meinung nach, wegen der Variablen Problem diskutiert in der Post, ist es besser, nur die "Controller als" -Technik zu verwenden und sie auch auf die Methoden anzuwenden.


15
2017-11-03 10:31



Frühere Versionen von Angular (vor 1.0 RC) erlaubten Ihnen dies zu benutzen   austauschbar mit der $ Scope-Methode, aber das ist nicht mehr die   Fall. Innerhalb von Methoden, die für den Bereich definiert sind, sind dies und $ scope   austauschbar (eckig setzt dies auf $ scope), aber nicht anders   in Ihrem Controller-Konstruktor.

Um dieses Verhalten zurückzubringen (weiß jemand, warum wurde es geändert?) Können Sie hinzufügen:

return angular.extend($scope, this);

am Ende Ihrer Controller-Funktion (vorausgesetzt, $ scope wurde in diese Controller-Funktion injiziert).

Dies hat einen schönen Effekt des Zugriffs auf den übergeordneten Bereich über das Controller-Objekt, mit dem Sie untergeordnete Objekte erhalten können require: '^myParentDirective'


3
2018-06-20 08:46



$ scope hat ein anderes 'dies' als der Controller 'this'. Wenn Sie also eine console.log (this) in den Controller setzen, erhalten Sie ein Objekt (Controller) und this.addPane () fügt dem Controller-Objekt addPane-Methode hinzu. Der $ scope hat jedoch einen anderen Gültigkeitsbereich und alle Methoden in diesem Bereich müssen von $ scope.methodName () aufgerufen werden. this.methodName() Inside-Controller bedeutet das Hinzufügen von Methoden innerhalb des Controller-Objekts.$scope.functionName() ist in HTML und innerhalb

$scope.functionName(){
    this.name="Name";
    //or
    $scope.myname="myname"//are same}

Füge diesen Code in deinen Editor ein und öffne die Konsole, um zu sehen ...

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
    <script>
        var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
          console.log("ctrl 'this'",this);
          //this(object) of controller different then $scope
          $scope.firstName="Andy";
          $scope.lastName="Bot";
          this.nickName="ABot";
          this.controllerMethod=function(){

            console.log("controllerMethod ",this);
          }
          $scope.show=function(){
              console.log("$scope 'this",this);
              //this of $scope
              $scope.message="Welcome User";
          }

        });
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
       Comming From $SCOPE :{{firstName}}
       <br><br>
       Comming from $SCOPE:{{lastName}}
       <br><br>
       Should Come From Controller:{{nickName}}
       <p>
            Blank nickName is because nickName is attached to 
           'this' of controller.
       </p>

       <br><br>
       <button ng-click="controllerMethod()">Controller Method</button>

       <br><br>
       <button ng-click="show()">Show</button>
       <p>{{message}}</p>

   </div>

</body>
</html>

0
2018-02-07 09:06