AngularJS におけるスコープ プロトタイプ / プロトタイプ継承のニュアンスは何ですか?
簡単な答え:
子スコープは通常、親からプロトタイプを継承します。範囲ですが、常にではありません。このルールの 1 つの例外は、スコープを持つディレクティブです: { ... } -- これは、プロトタイプ的に継承しない「分離」スコープを作成します。この構造は、「再利用可能なコンポーネント」ディレクティブを作成するときによく使用されます。
ニュアンスに関して言えば、スコープの継承は一般に簡単です...双方向のデータ バインディング (例: フォーム)要素、ng-model) を子スコープに含めます。子スコープ内から親スコープ内のプリミティブ (数値、文字列、ブール値など) にバインドしようとすると、ng-repeat、ng-switch、および ng-include につまずく可能性があります。ほとんどの人が期待しているようには機能しません。子スコープは、同じ名前の親プロパティを非表示/シャドウにする独自のプロパティを取得します。回避策は次のとおりです:
新しい AngularJS 開発者は、ng-repeat、ng-switch、ng-view、ng-include、ng-if がすべて新しい子スコープを作成することに気づいていないことがよくあります。多くの場合、これらのディレクティブが関係する場合に問題が発生します。 (問題の簡単な説明については、この例を参照してください。)
プリミティブに関するこの問題は、常に「.」を使用するという「ベスト プラクティス」に従うことで簡単に回避できます。 NG モデルで – 3 分ほど見てください。 Misko は、ng-switch の原始的なバインディングの問題を示しています。
「.」があるモデル内でプロトタイプの継承が確実に行われるようになります。したがって、使用します:
L-o-n-g Answer:
プロトタイプを理解する継承
スコープの継承について説明する前に、プロトタイプの継承を理解することが重要です。
parentScope にプロパティ aString、aNumber、anArray、anObject、および aFunction があるとします。 childScope がparentScope からプロトタイプ継承する場合、次のようになります。
[プロトタイプ継承図のイメージ]
parentScope で定義されたプロパティに子スコープからアクセスしようとすると、JavaScript は最初に子スコープでプロパティが見つからない場合は、継承されたスコープを調べてプロパティを見つけます。 (parentScope でプロパティが見つからなかった場合は、プロトタイプ チェーンを遡ってルート スコープまで続行します)。したがって、これらはすべて真実です:
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
次にこれを行うとします:
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
プロトタイプ チェーンは参照されず、新しい aString プロパティが childScope に追加されます。この新しいプロパティは、同じ名前のparentScopeプロパティを非表示/シャドウにします。これは、以下で ng-repeat と ng-include について説明するときに非常に重要になります。
[プロパティ隠蔽図のイメージ]
次に、次のようにするとします。
childScope.aString = 'child string'
オブジェクト (anArray と anObject) が childScope に見つからないため、プロトタイプ チェーンが参照されます。オブジェクトはparentScopeで見つかり、プロパティ値は元のオブジェクトで更新されます。新しいプロパティは childScope に追加されません。新しいオブジェクトは作成されません。 (JavaScript では、配列と関数もオブジェクトであることに注意してください。)
[プロトタイプのチェーン図に従うイメージ]
次に、次のようにするとします。
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
プロトタイプ チェーンは参照されず、子スコープは、同じプロパティでparentScope オブジェクト プロパティを非表示/シャドウにする 2 つの新しいオブジェクト プロパティを取得します。 names.
[その他のプロパティ隠蔽図のイメージ]
角度スコープの継承
候補:
デフォルトでは、ディレクティブは新しいスコープを作成しません (つまり、スコープ: false)。
ng-include
コントローラー:
childScope.anArray = [100, 555] childScope.anObject = { name: 'Mark', country: 'USA' }
そして、HTML 内:
$scope.myPrimitive = 50; $scope.myObject = {aNumber: 11};
各 ng-include は、プロトタイプとして親スコープから継承する新しい子スコープを生成します。
[ ng-include 子スコープ図のイメージ]
の入力 (たとえば、 "77") を最初の入力テキストボックスに入力すると、子スコープは、同じ名前の親スコープ プロパティを非表示/シャドウにする新しい myPrimitive スコープ プロパティを取得します。
[プリミティブ図を含む ng-include のイメージ]
2 番目の入力テキストボックスに入力 (たとえば「99」) しても、新しい子プロパティは生成されません。 tpl2.html はモデルをオブジェクト プロパティにバインドするため、ngModel がオブジェクト myObject を探すときにプロトタイプの継承が開始され、親スコープ内でそれが見つかります。
[オブジェクト図を含む ng-include のイメージ]
モデルをプリミティブからプリミティブに変更したくない場合は、$parent を使用するように最初のテンプレートを書き直すことができます。 object:
<script type="text/ng-template">
この入力テキストボックスに入力 (たとえば、「22」) しても、新しい子プロパティは生成されません。モデルは親スコープのプロパティにバインドされます ($parent は親スコープを参照する子スコープのプロパティであるため)。
[$parent 図を含む ng-include のイメージ]
ng-switch
NG-switch スコープの継承は、ng-include と同じように機能します。したがって、親スコープ内のプリミティブへの双方向データ バインディングが必要な場合は、$parent を使用するか、モデルをオブジェクトに変更してから、そのオブジェクトのプロパティにバインドします。これにより、子スコープの親スコープ プロパティの非表示/シャドウイングが回避されます。
ng-repeat
Ng-repeat の動作は少し異なります。コントローラー内に次があるとします:
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
そして HTML 内:
childScope.aString = 'child string'
項目/反復ごとに、ng-repeat はプロトタイプ的に親から継承する新しいスコープを作成します。スコープに追加されますが、項目の値も新しい子スコープの新しいプロパティに割り当てられます (新しいプロパティはループ変数名です)。 ng-repeat の Angular ソース コードは実際には次のとおりです。
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
項目がプリミティブ (myArrayOfPrimitives など) の場合、基本的に値のコピーが新しい子スコープ プロパティに割り当てられます。子スコープのプロパティの値を変更しても (つまり、ng-model を使用するため、子スコープの num が使用されます)、親スコープが参照する配列は変更されません。したがって、上記の最初の ng-repeat では、各子スコープは myArrayOfPrimitives 配列から独立した num プロパティを取得します。
[プリミティブ図を含む ng-repeat のイメージ]
This ng-repeat (あなたが望んでいる/期待しているように)機能しません。テキストボックスに入力すると、子スコープでのみ表示される灰色のボックス内の値が変更されます。私たちが望んでいるのは、入力が子スコープのプリミティブ プロパティではなく、myArrayOfPrimitives 配列に影響を与えることです。これを実現するには、モデルをオブジェクトの配列になるように変更する必要があります。
したがって、項目がオブジェクトの場合は、元のオブジェクト (コピーではなく) への参照が新しい子スコープに割り当てられます。財産。子スコープのプロパティの値を変更すると (つまり、ng-model、つまり obj.num を使用)、親スコープが参照するオブジェクトが変更されます。したがって、上記の 2 番目の ng-repeat では、次のようになります:
[オブジェクト図を含む ng-repeat の画像]
(どこにあるかを明確にするために、1 行を灰色に色付けしました) )
これは期待どおりに機能します。
に入力中以上がプロトタイプの継承は AngularJS スコープの双方向データ バインディングでどのように機能しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。