| 一、概要 |
在AngularJS中,子作用域(child scope)基本上都要继承自父作用域(parent scope)。
但,事无绝对,也有特例,那就是指令中scope设置项为对象时,即scope:{…},这将会让指令创建一个并不继承自父作用域的子作用域,我们称之为隔离作用域(isolated scope)。
指令中的scope一共可以有三个值,下面我们再来温习下:
|
指令之scope |
|
|
scope: false |
默认值,指令不会新建一个作用域,使用父级作用域。 |
|
scope: true |
指令会创建一个新的子作用域,原型继承于父级作用域。 |
|
scope: {…} |
指令会新建一个隔离作用域,不会原型继承父作用域。 |
那么,理解AngularJS中作用域继承有什么用呢?
原因之一就是,有利于我们使用“双向绑定”(也就是在form表单元素中绑定ng-model),例如,在初学AngularJS时,我们常会遇到“双向绑定”不起作用的时候,如下:
<!DOCTYPE html> <head> <meta charset="utf-8"/> <script src="angular.js"></script> </head> <body ng-app="myApp"> parent:<input type="text" ng-model="name"/> <div ng-controller="TestCtrl"> child: <input type="text" ng-model="name"/> </div> <script> var app = angular.module('myApp', []); app.controller('TestCtrl', function(){}); </script> </body> </html>
执行上述代码,结果如下:
其实AngularJS的作用域继承与JavaScript的原型继承是一样的逻辑,固,如果想要上述代码实现双向绑定,我们可以利用ng-model绑定对象属性,来达到目的,如下:
<!DOCTYPE html> <head> <meta charset="utf-8"/> <script src="angular.js"></script> </head> <body ng-app="myApp"> parent:<input type="text" ng-model="obj.name"/> <div ng-controller="TestCtrl"> child: <input type="text" ng-model="obj.name"/> </div> <script> var app = angular.module('myApp', []); app.run(function($rootScope){ $rootScope.obj = {}; }); app.controller('TestCtrl', function(){}); </script> </body> </html>
执行上述代码,结果如下:
该篇博客原文地址:http://www.cnblogs.com/giggle/p/5769047.html
| 二、JavaScript原型继承 |
上面已经提到了AngularJS的作用域继承与JavaScript的原型继承是一样儿一样儿的,所以,我们首先来初步温习下JavaScript的原型继承。
假设,我们有父作用域(ParentScope),且其中包含了属性aString、aNumber、anArray、anObject 以及aFunction。
好了,如果现在有一子作用域(ChildScope)继承于这个父作用域(ParentScope),如下所示:
当我们通过ChildScope想访问一个属性时,JavaScript内部是如何为我们查找的呢?
答案:
首先JavaScript会第一时间在当前作用域(如这里的ChildScope)中查找是否有这一属性,如果在当前作用域中没有找到,
那么JavaScript就会沿着原型这条链(如这里的:ChildScope-->ParentScope-->RootScope),一直找下去,倘若在某一父作用域中找到,就返回这个属性值并停止原型链查找;
倘若一直找到根作用域(如这里的RootScope)都没有找到,则返undefined。
故而,下面这些表达式,结果都为true:
childScope.aString === 'parent string' //true childScope.anArray[1] === 20 //true childScope.anObject.property1 === 'parent prop1' //true childScope.aFunction() === 'parent output' //true
好了,假如,我们这么做呢:
childScope.aString = 'child string'
那么只会在childScope中新建一个值为’child string’的aString属性。在这之后,倘若我们还想通过childScope访问parentScope中aString属性时,就束手无策了。
因为childScope已经有了一个aString属性。理解这一点是非常重要的,在我们讨论ng-repeat 和ng-include之前。
接下来,我们再这么做呢:
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
这样会沿着原型链查找的,并改变属性中的值。
为什么呢?
原因就是我们这次赋值的是对象中的属性。
好了,接下来,我们再这么做:
childScope.anArray = [100, 555]
childScope.anObject = {name: 'Mark', country: 'USA'}
这样做的效果,如同上面childScope.aString = ‘child string’一样,不会启动原型链查找。
总结:
1、如果我们读取子作用域的属性时,且该子作用域有这个属性,则不会启动原型链查找;
2、如果我们赋值子作用域的属性时,依然不会启动原型链查找。
1、If we read childScope.propertyX, and childScope has propertyX, then the prototype chain is not consulted.
2、If we set childScope.propertyX, the prototype chain is not consulted.