Quick answer :
(快速解答 :)
A child scope normally prototypically inherits from its parent scope, but not always.(子作用域通常从其父作用域继承,但并非总是如此。)
One exception to this rule is a directive with scope: { ... }
-- this creates an "isolate" scope that does not prototypically inherit.(该规则的一个例外是带有scope: { ... }
的指令scope: { ... }
-这会创建一个“隔离”范围,该范围不会被原型继承。)
This construct is often used when creating a "reusable component" directive.(创建“可重用组件”指令时,经常使用此构造。)
As for the nuances, scope inheritance is normally straightfoward... until you need 2-way data binding (ie, form elements, ng-model) in the child scope.
(对于细微差别,作用域继承通常是直截了当的……直到您需要在子作用域中进行2路数据绑定 (即,表单元素,ng-model)。)
Ng-repeat, ng-switch, and ng-include can trip you up if you try to bind to a primitive (eg, number, string, boolean) in the parent scope from inside the child scope.(如果您尝试从子作用域内部绑定到父作用域中的原始值 (例如,数字,字符串,布尔值),则Ng-repeat,ng-switch和ng-include可能会使您绊倒。)
It doesn't work the way most people expect it should work.(它不能像大多数人期望的那样工作。)
The child scope gets its own property that hides/shadows the parent property of the same name.(子作用域具有其自己的属性,该属性隐藏/阴影相同名称的父属性。)
Your workarounds are(您的解决方法是)
- define objects in the parent for your model, then reference a property of that object in the child: parentObj.someProp
(在模型的父级中定义对象,然后在子级中引用该对象的属性:parentObj.someProp)
- use $parent.parentScopeProperty (not always possible, but easier than 1. where possible)
(使用$ parent.parentScopeProperty(并非总是可能,但比1容易))
- define a function on the parent scope, and call it from the child (not always possible)
(在父作用域上定义一个函数,然后从子作用域调用它(并非总是可能的))
New AngularJS developers often do not realize that ng-repeat
, ng-switch
, ng-view
, ng-include
and ng-if
all create new child scopes, so the problem often shows up when these directives are involved.
(新的AngularJS开发人员通常不会意识到ng-repeat
, ng-switch
, ng-view
, ng-include
和ng-if
都会创建新的子范围,因此当涉及这些指令时,常常会出现问题。)
(See this example for a quick illustration of the problem.)((有关此问题的快速说明,请参见此示例。))
This issue with primitives can be easily avoided by following the "best practice" of always have a '.'
(通过遵循始终具有“' ”的“最佳实践”,可以很容易地避免使用基元出现此问题。)
in your ng-models – watch 3 minutes worth.(在您的ng模型中 -观看3分钟值得。)
Misko demonstrates the primitive binding issue with ng-switch
.(Misko演示了ng-switch
的原始绑定问题。)
Having a '.'
(有一个 '。')
in your models will ensure that prototypal inheritance is in play.(在您的模型中,将确保原型继承在起作用。)
So, use(所以用)
<input type="text" ng-model="someObj.prop1">
<!--rather than
<input type="text" ng-model="prop1">`
-->
Long answer :
(长答案 :)
JavaScript Prototypal Inheritance(JavaScript原型继承)
Also placed on the AngularJS wiki: https://github.com/angular/angular.js/wiki/Understanding-Scopes
(也放在AngularJS Wiki上: https : //github.com/angular/angular.js/wiki/Understanding-Scopes)
It is important to first have a solid understanding of prototypal inheritance, especially if you are coming from a server-side background and you are more familiar with class-ical inheritance.
(首先,必须对原型继承有扎实的了解,尤其是如果您来自服务器端背景并且对类继承更为熟悉时,这一点很重要。)
So let's review that first.(因此,让我们先回顾一下。)
Suppose parentScope has properties aString, aNumber, anArray, anObject, and aFunction.
(假设parentScope具有属性aString,aNumber,anArray,anObject和aFunction。)
If childScope prototypically inherits from parentScope, we have:(如果childScope原型继承自parentScope,则我们具有:)
(Note that to save space, I show the anArray
object as a single blue object with its three values, rather than an single blue object with three separate gray literals.)
((请注意,为了节省空间,我将anArray
对象显示为具有三个值的单个蓝色对象,而不是显示具有三个单独的灰色文字的单个蓝色对象。))
If we try to access a property defined on the parentScope from the child scope, JavaScript will first look in the child scope, not find the property, then look in the inherited scope, and find the property.
(如果我们尝试从子作用域访问在parentScope上定义的属性,JavaScript将首先在子作用域中查找,而不是查找该属性,然后在继承的作用域中查找并找到该属性。)
(If it didn't find the property in the parentScope, it would continue up the prototype chain... all the way up to the root scope).((如果未在parentScope中找到该属性,它将在原型链上一直延续到根范围)。)
So, these are all true:(所以,这些都是对的:)
childScope.aString === 'parent string' childScope.anArray[1] === 20 childScope.anObject.property1 === 'parent prop1' childScope.aFunction() === 'parent output'
Suppose we then do this:
(假设我们然后这样做:)
childScope.aString = 'child string'
The prototype chain is not consulted, and a new aString property is added to the childScope.
(未查询原型链,并且将新的aString属性添加到childScope。)
This new property hides/shadows the parentScope property with the same name.(此新属性将隐藏/隐藏具有相同名称的parentScope属性。)
This will become very important when we discuss ng-repeat and ng-include below.(当我们在下面讨论ng-repeat和ng-include时,这将变得非常重要。)
Suppose we then do this:
(假设我们然后这样做:)
childScope.anArray[1] = '22' childScope.anObject.property1 = 'child prop1'
The prototype chain is consulted because the objects (anArray and anObject) are not found in the childScope.
(之所以查询原型链,是因为在childScope中找不到对象(anArray和anObject)。)
The objects are found in the parentScope, and the property values are updated on the original objects.(在parentScope中找到对象,并且在原始对象上更新属性值。)
No new properties are added to the childScope;(没有向childScope添加任何新属性;)
no new objects are created.(没有创建新对象。)
(Note that in JavaScript arrays and functions are also objects.)((请注意,在JavaScript中,数组和函数也是对象。))
Suppose we then do this:
(假设我们然后这样做:)
childScope.anArray = [100, 555] childScope.anObject = { name: 'Mark', country: 'USA' }
The prototype chain is not consulted, and child scope gets two new object properties that hide/shadow the parentScope object properties with the same names.
(不查询原型链,子作用域将获得两个新的对象属性,这些对象属性将隐藏/阴影具有相同名称的parentScope对象属性。)
Takeaways:
(外卖:)
One last scenario:
(最后一种情况:)
delete childScope.anArray childScope.anArray[1] === 22 // true
We deleted the childScope property first, then when we try to access the property again, the prototype chain is consulted.
(我们首先删除了childScope属性,然后当我们再次尝试访问该属性时,将查询原型链。)
Angular Scope Inheritance(角范围继承)
The contenders:
(竞争者:)
Note, by default, directives do not create new scope -- ie, the default is scope: false
.
(注意,默认情况下,伪指令不会创建新的作用域-即默认值为scope: false
。)
ng-include(ng-include)
Suppose we have in our controller:
(假设我们在控制器中:)
$scope.myPrimitive = 50; $scope.myObject = {aNumber: 11};
And in our HTML:
(在我们的HTML中:)
<script type="text/ng-template" id="/tpl1.html"> <input ng-model="myPrimitive"> </script> <div ng-include src="'/tpl1.html'"></div> <script type="text/ng-template" id="/tpl2.html"> <input ng-model="myObject.aNumber"> </script> <div ng-include src="'/tpl2.html'"></div>
<p