AngularJS 中的 $scope 是什么?附带示例的教程
⚡ 智能摘要
在 AngularJS 中,`$Scope` 是一个内置对象,用于将控制器与其视图绑定。本页解释了作用域的创建、行为函数、父子层级结构、与 `$rootScope` 的区别,以及摘要循环如何刷新绑定。
AngularJS 中的 $scope 是什么?
AngularJS 中的 $scope 是一个内置对象,它基本上绑定了“控制器”和“视图”。可以在控制器的范围内定义成员变量,然后视图可以访问这些变量。
每个控制器 AngularJS 应用程序通过依赖注入获得自己的 $scope 实例。任何附加到该对象的内容都会对控制器所管理的模板可见,因此 $scope 充当了位于应用程序和模板之间的共享数据模型。 Java脚本逻辑和你的 HTML 标记。
请考虑以下示例:
angular.module('app',[]).controller('HelloWorldCtrl', function($scope) { $scope.message = "Hello World" });
Code 说明:
- 模块名称为“app”
- 控制器的名称是“HelloWorldCtrl”。
- 范围对象是用于将信息从控制器传递到视图的主要对象。
- 成员变量已添加到范围对象
⚠️ 语法警告: 此 .controller() 该方法接受两个参数:控制器名称和工厂函数,因此两者之间需要用逗号分隔。 'HelloWorldCtrl' 和 function($scope)省略逗号会导致错误 Uncaught SyntaxError 在 AngularJS 启动之前。
单个控制器和单个视图只是问题的一半。实际应用中,控制器会嵌套,列表会重复使用,控件也会重用,这意味着同时存在多个作用域。
AngularJS 中的作用域层次结构和继承是如何运作的
每个 AngularJS 应用程序都只有一个根作用域,但可以有任意数量的子作用域。指令创建这些子作用域并将它们附加到它们所修饰的 DOM 元素上,因此作用域树反映了渲染页面的结构。
当 AngularJS 计算如下表达式时: {{siteName}}它首先在元素所属的作用域中查找该属性。如果该属性不存在,则查找范围会扩展到父作用域,并不断向上追溯,直到到达根作用域。 Java脚本开发者将这种行为称为原型继承,子作用域正是以这种方式继承自父作用域。
下面的示例将一个控制器嵌套在另一个控制器中,以便您可以观察继承过程。
<div ng-app="scopeDemo"> <div ng-controller="ParentCtrl"> Parent scope value: {{siteName}} <div ng-controller="ChildCtrl"> Child reads parent value: {{siteName}} Child own value: {{lesson}} </div> </div> </div> <script type="text/javascript"> var app = angular.module("scopeDemo", []); app.controller("ParentCtrl", function($scope) { $scope.siteName = "Guru99"; }); app.controller("ChildCtrl", function($scope) { $scope.lesson = "AngularJS Scope"; }); </script>
Code 说明:
ParentCtrl定义siteName就其自身范围而言。ChildCtrl从未定义siteName然而,内部的div仍然会打印出来。 Guru99 因为查找操作会向上追溯到父级作用域。lesson它只存在于子作用域中,因此父 div 无法读取它。
哪些指令会创建新的作用域?
- ng-controller: 为它所在的元素创建一个子作用域。
- ng-repeat: 每次迭代创建一个子作用域,这就是为什么同一表达式的每一行可以包含不同的值。
- 自定义指令: 可以要求使用儿童瞄准镜,或者 隔离 故意不继承其父级的作用域。
- 组件指令: 任何已在以下机构注册的
.component()辅助函数始终接收一个隔离作用域。
由于子作用域是向上读取的,开发者常常会想知道这条链的顶端在哪里。这个顶层对象叫做 $rootScope。
$scope 与 $rootScope:有什么区别?
AngularJS $rootScope `$rootScope` 是整个应用程序的作用域。一个应用程序只能有一个 `$rootScope`,它像全局变量一样使用。每个 `$scope` 都是一个子作用域,而 `$rootScope` 是位于作用域树顶端的父作用域。下表比较了这两个对象。
| 方面 | 范围 | $rootScope |
|---|---|---|
| 每个应用程序的实例数 | 多个,每个控制器或作用域创建指令一个 | 正好一个 |
| 创建者 | ng-controller 和 ng-repeat 等指令 | 应用程序引导期间的注入器 |
| 提升品牌曝光性 | 它自身的元素及其所有后代 | 应用程序中的每个作用域 |
| 典型用途 | 一个视图或一个列表行的数据和行为 | 应用程序范围的值,例如已登录用户 |
| 主要风险 | 分支外部的值变得无法访问 | 名称冲突和隐藏耦合,例如全局变量 |
谨慎使用 `$rootScope`。任何放置在那里的内容都会在整个应用程序中存在,并且可以被任何地方读取,因此共享服务通常是存放全局状态的更安全选择。官方 $rootScope 引用 列出完整的 API。
了解数据存储位置只是工作的一半。另一半是教会范围如何响应用户的操作。
在 AngularJS 中设置或添加行为
为了对事件做出反应或在视图中执行某种计算/处理,我们必须为范围提供行为。
行为被添加到范围对象以响应视图可能触发的特定事件。一旦在控制器中定义了行为,视图就可以访问它。
让我们看一个例子来了解如何实现这一点。
<!DOCTYPE html> <html lang="en"> <head> <meta chrset="UTF 8"> <title>Guru99</title> </head> <body ng-app="DemoApp"> <h1> Guru99 Global Event</h1> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <div ng-controller="DemoController"> {{fullName("Guru","99")}} </div> <script type="text/javascript"> var app = angular.module("DemoApp", []); app.controller("DemoController", function($scope) { $scope.fullName=function(firstName,lastname){ return firstName + lastname; } } ); </script> </body> </html>
Code 说明:
- 我们正在创建一个名为“fullName”的行为。此行为是一个接受 2 个参数(firstName、lastname)的函数。
- 然后,行为返回这两个参数的连接。
- 在视图中,我们调用了该行为并传入了两个值“Guru“ ”和“99”作为参数传递给该行为。
如果命令成功执行,则在浏览器中运行代码时将显示以下输出。
输出:
在浏览器中,您将看到这两个值的连接结果。 Guru 99 个被传递给了行为 调节器.
像上面这样的绑定会自动刷新,在应用程序规模扩大之前,了解实现这一功能的机制是值得的。
为什么范围观察者和摘要周期如此重要
AngularJS 通过脏检查而非变更事件来保持视图与作用域的同步。三个作用域 API 驱动着这一过程:
- $watch: 为表达式注册监听器。例如,插值
{{fullName}}在模板链接期间为您注册关注者。 - $apply: 它会进入 AngularJS 执行上下文,执行你的代码,然后触发摘要。它仅在自定义事件回调或第三方库回调中需要,因为内置指令已经调用了它。
- 摘要: 遍历 $rootScope 及其子级上的每个监视器,将当前值与前一个值进行比较,并重复此过程,直到模型不再改变。
由于摘要信息可能需要多次遍历,因此监视表达式必须保持低开销。应避免在监视表达式内部访问 DOM,因为读取 DOM 的速度比读取摘要信息慢几个数量级。 Java脚本属性。
监测深度也会影响成本。通过参考值监测速度最快,但只有当整个值被替换时才会注意到。 $watchCollection 监听数组或对象中新增、删除或重新排序的元素。按值监听会在每次摘要时遍历嵌套结构,是开销最大的选项,因此应最后使用。




