AngularJS 中范围原型/原型继承的细微差别是什么?
快速回答:
子作用域通常继承自其父作用域,但并非总是如此。此规则的一个例外是范围为 { ... } 的指令——这会创建一个不典型继承的“隔离”范围。在创建“可重用组件”指令时经常使用此构造。
关于细微差别,范围继承通常很简单......直到您需要双向数据绑定(例如,表单elements, ng-model) 在子作用域中。如果您尝试从子作用域内绑定到父作用域中的基元(例如数字、字符串、布尔值),ng-repeat、ng-switch 和 ng-include 可能会让您陷入困境。它并不像大多数人期望的那样工作。子作用域拥有自己的属性,该属性隐藏/隐藏同名的父属性。您的解决方法是:
新的 AngularJS 开发人员通常没有意识到 ng-repeat、ng-switch、ng-view、ng-include 和 ng-if 都会创建新的子作用域,所以问题当涉及到这些指令时经常会出现。 (请参阅此示例以快速说明问题。)
通过遵循始终使用“.”的“最佳实践”,可以轻松避免原语的此问题。在您的 ng-models 中 – 观看 3 分钟。 Misko 演示了 ng-switch 的原始绑定问题。
有一个“.”在您的模型中将确保原型继承发挥作用。所以,使用:
L-o-n-g 答案:
理解原型继承
在讨论范围继承之前了解原型继承非常重要。
假设parentScope 具有属性aString、aNumber、anArray、anObject 和aFunction。如果childScope原型继承自parentScope,我们有:
[原型继承图的图像]
如果我们尝试从子作用域访问parentScope上定义的属性,JavaScript将首先查找在子作用域中,找不到该属性,然后在继承作用域中查找,并找到该属性。 (如果它在父作用域中没有找到该属性,它将沿着原型链继续向上......一直到根作用域)。所以,这些都是真的:
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'
不参考原型链,并在 childScope 中添加一个新的 aString 属性。这个新属性隐藏/隐藏了同名的parentScope属性。当我们下面讨论 ng-repeat 和 ng-include 时,这一点将变得非常重要。
[属性隐藏图的图像]
假设我们这样做:
childScope.aString = 'child string'
由于在 childScope 中未找到对象(anArray 和 anObject),因此查阅了原型链。在parentScope 中找到对象,并在原始对象上更新属性值。 childScope 中没有添加新属性;没有创建新对象。 (请注意,在 JavaScript 中数组和函数也是对象。)
[遵循原型链图的图像]
假设我们这样做:
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
不参考原型链,子作用域获取两个新的对象属性,这些属性隐藏/隐藏具有相同名称的父作用域对象属性。
[Image更多属性隐藏图]
Angular 作用域继承
竞争者:
默认情况下,指令不会创建新作用域(即,scope: 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 图像]
在第二个输入文本框中键入(例如“99”)不会产生一个新的子属性。因为 tpl2.html 将模型绑定到对象属性,所以当 ngModel 查找对象 myObject 时,原型继承就会启动——它在父作用域中找到它。
[带有对象图的 ng-include 图像]
如果我们不想将模型从原始模型更改为原始模型,我们可以重写第一个模板以使用 $parent object:
<script type="text/ng-template">
在此输入文本框中键入(例如“22”)不会产生新的子属性。该模型现在绑定到父作用域的属性(因为 $parent 是引用父作用域的子作用域属性)。
[ng-include 与 $parent 图的图像]
ng-开关
NG-switch 作用域继承的工作方式与 ng-include 类似。因此,如果您需要与父作用域中的原语进行 2 路数据绑定,请使用 $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 图像]
这个 ng-repeat不会起作用(就像你想要/期望的那样)。在文本框中键入内容会更改灰色框中的值,这些值仅在子范围中可见。我们想要的是输入影响 myArrayOfPrimitives 数组,而不是子范围基元属性。为了实现这一点,我们需要将模型更改为对象数组。
因此,如果该项目是一个对象,则将对原始对象(而不是副本)的引用分配给新的子作用域财产。更改子作用域属性的值(即使用 ng-model,因此使用 obj.num)确实会更改父作用域引用的对象。因此,在上面的第二个 ng-repeat 中,我们有:
[带有对象图的 ng-repeat 图像]
(我将一条线涂成灰色,以便清楚地显示在哪里)它正在运行。)
这按预期工作。输入
以上是原型继承如何与 AngularJS 作用域中的双向数据绑定一起工作?的详细内容。更多信息请关注PHP中文网其他相关文章!