1. ホーム
  2. angularjs

[解決済み] AngularJS コントローラにおける 'this' と $scope の比較

2022-03-16 14:51:24

質問

AngularJSのホームページの"Create Components"セクションにある には、このような例があります。

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);
  }
}

がどのように select メソッドが追加され $scope を指定する必要がありますが addPane メソッドが追加されます。 this . もし、これを $scope.addPane で、コードが壊れる。

ドキュメントには、実際に違いがあることは書かれていますが、その違いが何であるかについては触れられていません。

以前のバージョン(1.0 RC以前)のAngularでは this と互換性があります。 $scope メソッドがありますが、これはもはや事実ではありません。スコープ上で定義されたメソッドの内部で this$scope は交換可能です(角度セット this$scope ) を使用しますが、それ以外のコントローラコンストラクタ内では使用しません。

どのように this$scope は、AngularJSのコントローラで動作しますか?

どのように解決するのですか?

<ブロッククオート

どのように this$scope は、AngularJSのコントローラで動作するのですか?

短い回答 :

  • this
    • コントローラコンストラクタ関数が呼び出されたとき。 this がコントローラです。
    • に定義された関数が $scope オブジェクトが呼び出される。 this は、関数が呼び出されたときに有効だったスコープです" 。 このスコープが $scope で定義された関数です。 つまり、関数の内部で this$scope よろしい ない は同じです。
  • $scope
    • すべてのコントローラには、関連する $scope オブジェクトを作成します。
    • コントローラ (コンストラクタ) 関数は、モデルのプロパティを設定し、関連する $scope .
    • このメソッドで定義されたメソッドのみ $scope オブジェクト (およびプロトタイプ継承が行われている場合はその親スコープオブジェクト) に HTML/view からアクセスすることができます。 例えば ng-click , フィルタなど。

長い回答 :

コントローラ関数は、JavaScriptのコンストラクタ関数です。 コンストラクタ関数が実行されるとき(例えば、ビューがロードされるとき)。 this (すなわち、"function context") にコントローラオブジェクトが設定されます。つまり、コントローラのコンストラクタ関数において、addPane関数が生成される際に

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

は、コントローラオブジェクトで作成され、 $scope ではありません。 ビューは addPane 関数を見ることができません -- ビューは $scope で定義された関数にしかアクセスできません。 言い換えると、HTML上では、これは動作しません。

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

コントローラコンストラクタ関数が実行された後、以下のようになります。

黒の破線はプロトタイプの継承を示し、アイソレートのスコープはプロトタイプの継承で スコープ . (HTMLの中でそのディレクティブに出会ったときのスコープからは、プロトタイプ的に継承されません)。

さて、pane ディレクティブの link 関数は、tabs ディレクティブと通信したいと考えています (つまり、tabs isolate $scope に何らかの形で影響を与える必要があるということです)。 イベントを使用することもできますが、他の方法として、ペインディレクティブが require をタブコントローラーに設定します。 (ペインディレクティブがタブコントローラになる仕組みはないようです。 require を指定します)。

もし、tabs コントローラにしかアクセスできないのなら、 (本当に必要な)tabs isolate $scope にはどのようにアクセスするのでしょうか?

さて、赤い点線がその答えです。 addPane() 関数の "scope" (ここでは JavaScript の関数スコープ/クロージャを参照しています) は、タブ孤立 $scope へのアクセスを関数に与えています。 つまり、addPane() が上の図の "tabs IsolateScope" にアクセスできるのは、addPane() を定義したときに作成されたクロージャのためです。 (代わりに tabs $scope オブジェクトに addPane() を定義した場合、pane ディレクティブはこの関数にアクセスできず、したがって tabs $scope と通信する方法がありません)。

質問のもう一つの部分にお答えします。 how does $scope work in controllers? :

scopeで定義された関数内。 this には、その関数が呼び出された場所/時に有効な$scopeが設定されます"。 例えば、以下のようなHTMLがあったとします。

<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>

そして ParentCtrl (ソール)には

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

最初のリンクをクリックすると、次のように表示されます。 this$scope は同じなので、" この関数が呼び出されたときに有効だったスコープ に関連付けられたスコープです。 ParentCtrl .

2つ目のリンクをクリックすると this$scope ではない は同じなので、"。 この関数が呼び出されたときに有効だったスコープ に関連付けられているスコープです。 ChildCtrl . そこで、ここでは this が設定されています。 ChildCtrl 's $scope . メソッドの内部で $scope は、やはり ParentCtrl の$scopeを使用します。

フィドル

を使用しないようにしています。 this ng-repeat、ng-include、ng-switch、およびディレクティブがすべて独自の子スコープを作成できることを特に考慮して、どの$scopeが影響を受けるのかがわからなくなるためです。