Maison >interface Web >js tutoriel >Comment l'héritage prototypique fonctionne-t-il avec la liaison de données bidirectionnelle dans les étendues AngularJS ?
Quelles sont les nuances de l'héritage prototypique/prototypique de portée dans AngularJS ?
Réponse rapide :
Une portée enfant hérite généralement de manière prototypique de sa portée parent, mais pas toujours. Une exception à cette règle est une directive avec scope : { ... } -- cela crée une portée "isoler" qui n'hérite pas de manière prototypique. Cette construction est souvent utilisée lors de la création d'une directive "composant réutilisable".
En ce qui concerne les nuances, l'héritage de portée est généralement simple... jusqu'à ce que vous ayez besoin d'une liaison de données bidirectionnelle (par exemple, un formulaire éléments, ng-model) dans la portée enfant. Ng-repeat, ng-switch et ng-include peuvent vous faire trébucher si vous essayez de vous lier à une primitive (par exemple, un nombre, une chaîne, un booléen) dans la portée parent depuis l'intérieur de la portée enfant. Cela ne fonctionne pas comme la plupart des gens l’attendent. La portée enfant obtient sa propre propriété qui masque/masque la propriété parent du même nom. Vos solutions de contournement sont :
Les nouveaux développeurs AngularJS ne réalisent souvent pas que ng-repeat, ng-switch, ng-view, ng-include et ng-if créent tous de nouvelles étendues enfants, donc le problème est souvent apparaît lorsque ces directives sont impliquées. (Voir cet exemple pour une illustration rapide du problème.)
Ce problème avec les primitives peut être facilement évité en suivant la « meilleure pratique » consistant à toujours avoir un '.' dans vos modèles ng – regardez 3 minutes. Misko démontre le problème de liaison primitive avec ng-switch.
Avoir un '.' dans vos modèles garantira que l’héritage prototypique est en jeu. Alors, utilisez :
L-o-n-g Réponse :
Comprendre l'héritage prototypique
C'est important pour comprendre l'héritage prototypique avant de discuter de l'héritage de portée.
Supposons que parentScope ait les propriétés aString, aNumber, anArray, anObject et aFunction. Si childScope hérite de manière prototypique de parentScope, nous avons :
[Image du diagramme d'héritage prototypique]
Si nous essayons d'accéder à une propriété définie sur parentScope à partir de la portée enfant, JavaScript examinera d'abord la portée enfant, ne trouvez pas la propriété, puis regardez dans la portée héritée et trouvez la propriété. (S'il ne trouvait pas la propriété dans parentScope, il continuerait dans la chaîne des prototypes... jusqu'à la portée racine). Donc, tout cela est vrai :
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
Supposons que nous fassions alors ceci :
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
La chaîne de prototypes n'est pas consultée, et une nouvelle propriété aString est ajoutée au childScope. Cette nouvelle propriété masque/ombre la propriété parentScope du même nom. Cela deviendra très important lorsque nous discuterons de ng-repeat et ng-include ci-dessous.
[Image du diagramme de masquage des propriétés]
Supposons que nous fassions ensuite ceci :
childScope.aString = 'child string'
La chaîne de prototypes est consultée car les objets (anArray et anObject) ne sont pas trouvés dans le childScope. Les objets sont trouvés dans parentScope et les valeurs des propriétés sont mises à jour sur les objets d'origine. Aucune nouvelle propriété n’est ajoutée à childScope ; aucun nouvel objet n'est créé. (Notez qu'en JavaScript, les tableaux et les fonctions sont également des objets.)
[Image de suivre le diagramme de chaîne du prototype]
Supposons que nous fassions ensuite ceci :
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
Le La chaîne de prototypes n'est pas consultée et la portée enfant obtient deux nouvelles propriétés d'objet qui masquent/masquent les propriétés de l'objet parentScope portant les mêmes noms.
[Image de plus de propriétés diagramme masqué]
Héritage de portée angulaire
Les prétendants :
Par défaut, les directives ne créent pas de nouvelle portée (c'est-à-dire, portée : false).
ng-include
Supposons que nous ayons dans notre contrôleur :
childScope.anArray = [100, 555] childScope.anObject = { name: 'Mark', country: 'USA' }
Et dans notre HTML :
$scope.myPrimitive = 50; $scope.myObject = {aNumber: 11};
Chaque ng-include génère une nouvelle portée enfant, qui hérite de manière prototypique de la portée parent.
[Image du diagramme des portées enfants ng-include]
En tapant (par exemple, "77") dans la première zone de texte d'entrée, la portée enfant obtient une nouvelle propriété de portée myPrimitive qui masque/masque la portée parent. propriété du même nom.
[Image de ng-include avec un diagramme primitif]
Taper (par exemple, "99") dans la deuxième zone de texte d'entrée ne génère pas de nouvelle propriété enfant . Étant donné que tpl2.html lie le modèle à une propriété d'objet, l'héritage prototypique entre en jeu lorsque le ngModel recherche l'objet myObject - il le trouve dans la portée parent.
[Image de ng-include avec un diagramme d'objet]
Nous pouvons réécrire le premier modèle pour utiliser $parent, si nous ne voulons pas changer notre modèle d'un primitif à un object :
<script type="text/ng-template">
Taper (par exemple, "22") dans cette zone de texte d'entrée n'entraîne pas la création d'une nouvelle propriété enfant. Le modèle est maintenant lié à une propriété de la portée parent (car $parent est une propriété de portée enfant qui fait référence à la portée parent).
[Image de ng-include avec diagramme $parent]
ng-switch
L'héritage de portée Ng-switch fonctionne comme ng-include. Donc, si vous avez besoin d'une liaison de données bidirectionnelle à une primitive dans la portée parent, utilisez $parent ou modifiez le modèle pour qu'il soit un objet, puis liez-le à une propriété de cet objet. Cela évitera que la portée enfant ne masque/masque les propriétés de la portée parent.
ng-repeat
Ng-repeat fonctionne un peu différemment. Supposons que nous ayons dans notre contrôleur :
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
Et dans notre HTML :
childScope.aString = 'child string'
Pour chaque élément/itération, ng-repeat crée une nouvelle portée, qui hérite de manière prototypique du parent scope, mais il attribue également la valeur de l'élément à une nouvelle propriété sur la nouvelle portée enfant (la nouvelle propriété est le nom de la variable de boucle). Voici ce qu'est réellement le code source angulaire de ng-repeat :
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
Si l'élément est une primitive (comme dans myArrayOfPrimitives), essentiellement une copie de la valeur est affectée à la nouvelle propriété de portée enfant. Changer la valeur de la propriété de portée enfant (c'est-à-dire utiliser ng-model, donc numéro de portée enfant) ne modifie pas le tableau auquel la portée parent fait référence. Ainsi, dans le premier ng-repeat ci-dessus, chaque portée enfant obtient une propriété num indépendante du tableau myArrayOfPrimitives :
[Image de ng-repeat avec diagramme de primitives]
Ce ng-repeat ne fonctionnera pas (comme vous le souhaitez/attendez). La saisie dans les zones de texte modifie les valeurs dans les zones grises, qui ne sont visibles que dans les étendues enfants. Ce que nous voulons, c'est que les entrées affectent le tableau myArrayOfPrimitives, et non une propriété primitive de portée enfant. Pour ce faire, nous devons modifier le modèle pour qu'il soit un tableau d'objets.
Ainsi, si l'élément est un objet, une référence à l'objet d'origine (et non une copie) est attribuée à la nouvelle portée enfant. propriété. La modification de la valeur de la propriété de portée enfant (c'est-à-dire en utilisant ng-model, donc obj.num) modifie l'objet auquel la portée parent fait référence. Donc, dans le deuxième ng-repeat ci-dessus, nous avons :
[Image de ng-repeat avec diagramme d'objets]
(J'ai coloré une ligne en gris juste pour qu'il soit clair où ça va.)
Cela fonctionne comme prévu. Taper dans
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!