AngularJS转深入了解 AngularJS 的 Scope作用域

文章转载英文:what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs

         
 中文:http://www.lovelucy.info/understanding-scopes-in-angularjs.html

   一、AngularJS 中的 Scope(scope即作用域、作用范围)所关联知识点大致预览图

 AngularJS 1

   二、AngularJS中控制器间嵌套问题

在用 AngularJS 嵌套 Controller 的时。因为每个 Controller
都产生它们对应之 Scope(相当给作用域、控制范围),所以 Controller
的嵌套,也就是象征 Scope 的嵌套。

夫时段要简单单 Scope 内还来同名的 Model
会发生啊呢?从子 Scope
怎样翻新父 Scope 里的 Model 呢?

   2.1
父子嵌套控制器scope中属性名相同时(准确说基本数据列属性名)情况

以AngularJS中子scope会继承父scope中之目标,但当你试试下对着力数据列(string, number,
boolean)
的 双向数据绑定 时,子 Scope 的性隐藏(覆盖)了父 Scope 中的跟名属性,对子 Scope 属性(表单元素)的转移并无创新父 Scope 属性的价。

AngularJS 2

在线编代码  吁点击自己哦 这种行为其实不是 AngularJS
特有的,JavaScript 本身的原型链就是这样工作之。

开发者通常都并未意识及 ng-repeat,
ng-switch, ng-view 和 ng-include 统统都创造了她们新的子 scopes,所以当为此到这些 directive
时为不时闹问题。

   2.1 子 Scope 怎样翻新父 Scope 里之
Model 呢?

 解决方案一、不采用基本数据类,而在 Model 里永恒多加一个碰 <input
type=”text” ng-modal=”someObj.greeting”/>
变成对象形式 在线编代码请点击

 解决方案二、在子 Scope 中采取 $parent.greeting 这将阻止子 Scope
创建它和谐之属性。 在线编代码请点击

   三、JavaScript原型继承

 假设父类 parentScope 有如下成员属性 aString, aNumber, anArray,
anObject, 以及 aFunction。子类 childScope 原型继承父类
parentScope,于是我们来

AngularJS 3

若果子 Scope 尝试去拜访 parentScope 中定义的特性,JavaScript 会先在子
Scope 中摸索,如果没拖欠属性,则寻她继续的 scope
去取得属性,如果连续的原型对象 parentScope
中还未曾该属性,那么累以它们的原型中找,从原型链一直于上直到抵达
rootScope。所以,下面的表达式结果还是 true:

childScope.aString === 'parent string'
childScope.anArray[1] === 20
childScope.anObject.property1 === 'parent prop1'
childScope.aFunction() === 'parent output'

假使我们尽下的口舌

childScope.aString = 'child string'

原型链并没有让询问,反而是以 childScope 中益了一个新属性
aString。这个新属性隐藏(覆盖)了 parentScope
中之同名属性。在脚我们讨论 ng-repeat 和 ng-include 时之概念好关键。

AngularJS 4

childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'

原型链被询问了,因为对象 anArray 和 anObject 在 childScope
中从不找到。它们于 parentScope 中于找到了,并且值为更新。childScope
中尚无加新的性能,也绝非任何新的靶子吃创造。(注:在 JavaScript
中,array 和 function 都是目标)

AngularJS 5  

倘若我们执行是操作:

childScope.anArray = [100, 555]
childScope.anObject = { name: 'Mark', country: 'USA' }

原型链没有受询问,并且子 Scope
新在了少数独新的靶子属性,它们隐藏(覆盖)了 parentScope
中的同名对象属性。

AngularJS 6  

该好总结

  • 若读取
    childScope.propertyX,并且 childScope 有性
    propertyX,那么原型链没有被询问。
  • 设安
    childScope.propertyX,原型链不会被询问。

末一栽状况

delete childScope.anArray
childScope.anArray[1] === 22  // true

俺们从 childScope
删除了性,则当我们再次做客该属性时,原型链会被询问。删除对象的性能会被来原型链中的性浮现出来。

AngularJS 7

   四、AngularJS 的 Scope 继承

  • 创建新的 Scope,并且原型继承:ng-repeat, ng-include, ng-switch, ng-view,
    ng-controller, directive with scope: true, directive
    with transclude: true
  • 创造新的 Scope,但无继续:directive
    with scope: { ... }。它见面创造一个独门 Scope。

流动:默认情况下 directive 不创造新 Scope,即默认参数是 scope: false

ng-include  假设于我们的 controller 中

$scope.myPrimitive = 50;
$scope.myObject    = {aNumber: 11};

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>

每一个 ng-include 会生成一个子 Scope,每个子 Scope 都持续父 Scope。

AngularJS 8

输入(比如”77″)到第一单 input 文本框,则子 Scope 将抱一个初的
myPrimitive 属性,覆盖掉父 Scope 的同名属性。这或与你预想的未一致。

AngularJS 9

输入(比如”99″)到第二个 input 文本框,并无会见以子 Scope
创建新的性能,因为 tpl2.html 将 model 绑定到了一个对象属性(an object
property),原型继承在这时候发挥了作用,ngModel 寻找目标 myObject
并且以它的父 Scope 中找到了。

AngularJS 10  

假若我们无思拿 model 从 number 基础项目变更吗对象,我们可据此 $parent
改写第一只模板:

<input ng-model="$parent.myPrimitive">

输入(比如”22″)到之文本框也非会见创新特性了。model 于绑定到了父 scope
的性质上(因为 $parent 是子 Scope 指为它的父 Scope 的一个性能)。

AngularJS 11

对于拥有的 scope (原型继承的或非继承的),Angular 总是会透过 Scope 的
$parent, $$childHead 和 $$childTail
属性记录父-子关系(也就是继续关系),图备受呢简化而非画有这些性。

每当未曾表单元素的景象下,另一样种艺术是当父 Scope
中定义一个函数来窜基本数据类。因为来原型继承,子 Scope
确保能够调用这个函数。例如,

// 父 Scope 中
$scope.setMyPrimitive = function(value) {
    $scope.myPrimitive = value;
}

查看
DEMO。参考 StackOverflow。 

ng-switch

ng-switch 的原型继承与 ng-include
一样。所以只要您得针对骨干类型数据进行双向绑定,使用
$parent,或者用该转移吗 object 对象并绑定到目标的属性,防止子 Scope 覆盖父
Scope 的性能。

参考 AngularJS, bind
scope of a
switch-case?

ng-repeat

ng-repeat 有几许未一致。假设以我们的 controller 里:

$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects    = [{num: 101}, {num: 202}]

还有 HTML:

<ul>
    <li ng-repeat="num in myArrayOfPrimitives">
       <input ng-model="num">
    </li>
<ul>
<ul>
    <li ng-repeat="obj in myArrayOfObjects">
       <input ng-model="obj.num">
    </li>
<ul>

于各级一个 Item,ng-repeat 创建新的 Scope,每一个 Scope 都累父
Scope,但还要 item 的值也深受给予给了新 Scope
的新属性(新属性的名啊循环的变量号称)。Angular ng-repeat
的源码实际上是这样的:

childScope = scope.$new(); // 子 scope 原型继承父 scope ...     
childScope[valueIdent] = value; // 创建新的 childScope 属性

只要 item 是一个基础数据类型(就比如
myArrayOfPrimitives),本质上它的价为复制了同样客与给了新的子 scope
属性。改变是子 scope 属性值(比如用 ng-model,即 num)不会见变动父
scope 引用的 array。所以地方第一个 ng-repeat 里各级一个子 scope
获得的 num 属性独立于 myArrayOfPrimitives 数组:

AngularJS 12

如此这般的 ng-repeat 和公预想着之莫一样。在 Angular 1.0.2
及重新早的版,向文本框中输入会转移灰色格子的值,它们仅仅于子 Scope
中可见。Angular 1.0.3+
以后,输入文本不见面再度来任何作用了。(参考 StackOverflow
上的讲)我们期望的是输入会更改
myArrayOfPrimitives 数组,而不是子 Scope 里的性能。为夫我们要将 model
改吧一个关于目标的数组(array of objects)。

据此一旦 item
是一个靶,则对此本对象的一个引用(而未拷贝)被与给了初的子 Scope
属性。改变子 Scope 属性的值(使用 ng-model,即 obj.num)也便变更了父
Scope 所引用的目标。所以地方第二只 ng-repeat 可代表为:

AngularJS 13

ng-controller

运用 ng-controller 进行嵌套,结果跟 ng-include 和 ng-switch
一样是常规的原型继承。所以做法也如出一辙不再赘述。然而“两单 controller 使用
$scope 继承来共享信息让看是不好的做法”(来自 这里),应该以
service 在 controller 间共享数据。

假若您真正要经持续来共享数据,那么为尚未什么独特而召开的,子 Scope
可以直接访问有父 Scope 的性。参考 Controller load
order differs when loading or
navigating

 

directives 分情况讨论

  1. 默认 scope: false – directive 不会见创新的
    Scope,所以没原型继承。这看起来挺粗略,但为大凶险,因为你见面当
    directive 在 Scope
    中创造了一个新的特性,而实际它只是用了一个既在的性能。这对准编写而复用的模块和零部件来说并无好。
  2. scope: true – 这时 directive 会创建一个新的子 scope 并继承父
    scope。如果以同一个 DOM 节点上发出差不多独 directive 都设创造新
    scope,则独自生一个初 Scope 会创建。因为有正规的原型继承,所以和
    ng-include, ng-switch 一样要专注基础项目数据的双向绑定,子 Scope
    属性会覆盖父 Scope 同名属性。
  3. scope: { ... } – 这时 directive 创建一个独自的
    scope,没有原型继承。这当编排而复用的模块和组件时是比较好之选料,因为
    directive 不见面不小心读写父 scope。然而,有时候这好像 directives
    又经常得拜访父 scope 的习性。对象散列(object
    hash)被用来确立这个独自 Scope 与父 Scope 间的双向绑定(使用
    ‘=’)或就为绑定(使用 ‘@’)。还有一个 ‘&’ 用来绑定父 Scope
    的表达式。这些统统由父 Scope 派生创建有地面的 Scope 属性。注意,HTML
    属性被用来建绑定,你无法以对象散列中援引父 Scope
    的属于性名,你不能不采取一个 HTML
    属性。例如,<div my-directive> 和 scope: { localProp: '@parentProp' } 是力不从心绑定父属性
    parentProp 到独门
    scope的,你得这样指定: <div my-directive the-Parent-Prop=parentProp> 以及 scope: { localProp: '@theParentProp' }。独立的
    scope 中 __proto__ 引用了一个 Scope 对象(下图被的桔黄色
    Object),独立 scope 的 $parent 指向父
    scope,所以尽管它们是独的以没有起父 Scope 原型继承,它仍是一个子
    scope。

    下面的图中,我们有 <my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2">和 scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
    又,假要 directive 在其的 link
    函数里做了 scope.someIsolateProp = "I'm isolated"

                      AngularJS 14

留神:在 link
函数中动用 attrs.$observe('attr_name', function(value) { ... } 来获取独立
Scope 用 ‘@’ 符号替换的属性值。例如,在 link
函数中出 attrs.$observe('interpolated', function(value) { ... } 值将给设为

  1. scope.interpolatedProp 在 link 函数中凡
    undefined,相反scope.twowayBindingProp 在 link 函数中定义了,因为用了
    ‘=’ 符号)
    又多参考 http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/

                4.transclude: true – 这时 directive 创建了一个初的
“transcluded” 子 scope,同时继续父
scope。所以如果模板片段中之始末(例如那些将替代 ng-transclude
的内容)要求针对父         Scope 的核心类型数据开展双向绑定,使用
$parent,或者用 model 一个靶的性,防止子 Scope 属性覆盖父 Scope
属性。

transcluded 和单身 scope (如果起)是兄弟关系,每个 Scope 的 $parent
指向同一个父 Scope。当模板被之 scope 和独立 Scope 同时有,独立 Scope
属性 $$nextSibling 将会晤对模板被之 Scope。更多关于 transcluded scope
的消息,参考 AngularJS two way
binding not working in directive with transcluded
scope。

在产图AngularJS中,假要 directive
和高达个图一律,只是多了 transclude: true

AngularJS 15

查看 在线
DEMO,例子里来一个
showScope() 函数可以为此来检查独立 Scope 和它们涉及的 transcluded scope。

  五、归纳总结

总计有四栽 Scope:

  1. 平常进行原型继承的 Scope —— ng-include, ng-switch, ng-controller,
    directive with scope: true
  2. 便原型继承的 Scope 但拷贝赋值 —— ng-repeat。 每个 ng-repeat
    的大循环都创新的子 Scope,并且子 Scope 总是获得新的性质。
  3. 独立的 isolate scope —— directive
    with scope: {...}。它不是原型继承,但 ‘=’, ‘@’ 和 ‘&’ 提供了顾父
    Scope 属性的建制。
  4. transcluded scope —— directive
    with transclude: true。它呢随原型继承,但它们以是任何 isolate
    scope 的哥们。

对持有的 Scope,Angular 总是会通过 Scope 的 $parent, $$childHead 和
$$childTail 属性记录父-子关系。

相关文章