首页 > 技术文章 > AngularJS $scope 继承性 作用 生命周期

shawnhu 原文

一、基本概念

  作用域是一个指向应用模型的对象,相当于MVVM中的ViewModel,能绑定数据(属性)和行为(方法),能监控表达式和传递事件,是实现双向绑定的基础,是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带,是连接视图和控制器的一个特殊的JavaScript对象。

  作用域是一个树型层次结构,与DOM标签平行,有根作用域,多个子作用域,子作用域下又有子作用域。所有的应用都有一个 $rootScope,它作用在 ng-app 指令包含的所有 HTML 元素中。$rootScope 可作用于整个应用中。是各个 controller 中 scope 的桥梁。用 rootscope 定义的值,可以在各个 controller 中使用。ng-app 指令可以产生一个根作用域之外,一些 指令会创建新的子作用域,并且进行原型继承,如 ng-repeat、ng-include、ng-switch、ng-view、ng-controller, 另外,用 scope: true 和 transclude: true 创建自定义 directive也会产生新作用域。

  作用域变量性质,有局部变量和全部变量之分,全局变量可以在方法,或者闭包内引入,而局部变量只能在定义的方法内使用,其他方法引用不到,$rootscope相当于全部变量,不应在 $rootScope附加太多的业务逻辑数据(全局),而是用控制器显示的创建 $scope对象来管理自己相关的逻辑和数据(局部)。

   作用域继承性,子作用域自动继承父作用域的属性和方法,如果自己有就用自己的同名属性和方法。有如下内部关系

    scope.$parent :指向scope的父作用域

    scope.$$childHead:指向scope的第一个子作用域

    scope.$$childTail:指向scope的最后一个子作用域

    scope.$$nextSibling:指向scope的下一个相邻作用域

    scope.$$prevSibling:指向scope的上一个相邻作用域

  例子:  

<html>
<head>
  <title>Angular JS</title>
</head>
<body>
  <h2>AngularJS Sample</h2>
  <!--绑定ng-app产生$rootscope,还有产生一个当前作用域$scope(shapeController),这里产生两个作用域-->
<!--message和type都显示自己的--> <div ng-app="mainApp" ng-controller="shapeController"> <p>{{message}} <br/> {{type}} </p>
  <!--产生一个子作用域(circleController)-->
  <!--message显示自己的,type没定义,就显示继承过来的type--> <div ng-controller="circleController"> <p>{{message}} <br/> {{type}} </p> </div>
  <!--产生另一个平行子作用域(squareController)-->
  <!--message和type都显示自己的,虽然和根作用域有继承关系--> <div ng-controller="squareController"> <p>{{message}} <br/> {{type}} </p> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script> <script> var mainApp = angular.module("mainApp", []);  //父控制器,产生父作用域 mainApp.controller("shapeController", function($scope) { $scope.message = "In shape controller"; $scope.type = "Shape"; });  //子作用域,没type,用父作用域的type mainApp.controller("circleController", function($scope) { $scope.message = "In circle controller"; });  //另一个平行子作用域,有type用自己的type mainApp.controller("squareController", function($scope) { $scope.message = "In square controller"; $scope.type = "Square"; }); </script> </body> </html>

二、作用域上的$watch()、$apply()方法

1、watch() 

  用于监听模型变化,当模型发生变化,它会提示你的。

  表达式: $watch(watchExpression, listener, objectEquality);

  其参数:

    watchExpression:监听的对象,它可以是一个angular表达式如'name',或函数如function(){return $scope.name}。

    listener:当watchExpression变化时会被调用的函数或者表达式,它接收3个参数:newValue(新值), oldValue(旧值), scope(作用域的引用)。

    objectEquality:是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化. 如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它。

$scope.name = 'hello';
var watch = $scope.$watch('name',function(newValue,oldValue, scope){
  console.log(newValue);
   console.log(oldValue);
});
$timeout(function(){
  $scope.name = "world";
},1000);

  在后台显示world,1秒后,会变成hello,$timeout内部会触发$scope.$apply()

2、$apply()

  用于传播模型的变化,如果一些javascript方法,如setTimeout,调用了AngularJS 函数之后,必须调用$apply。

$scope.test = function() {  
    setTimeout(function () {  
        $scope.$apply(function () {  
            $scope.user = "hello";  
        });  
    }, 2000);  
} 

 不能写成下边的代码,这样不能实现双向数据绑定。

$scope.test = function() {  
    setTimeout(function () {  
        $scope.user = "hello";  
    }, 2000);  
} 

三、作用

  1、提供了观察者可以监听数据模型的变化

  2、可以将数据模型的变化通知给整个 App

  3、可以进行嵌套,隔离业务功能和数据

  4、给表达式提供上下文执行环境

四、$socpe的生命周期

  scope的生命周期处理主要包含以下几个阶段:

  1、创建: AngularJS启动时,会使用 $injector创建一个根作用域,将作用域传进相应的控制器或指令中

    注意: AngularJS除了ng-controller和ng-repeat指令会创建自己的子作用域,一般不会创建自己的 $scope

  2、链接(注册观察者): AngularJS运行时,指令会创建自己的作用域,所有的 $scope对象都会链接到视图上,通过注册 $watch函数来获取数据变化通知

  3、模型状态改变:更新模型状态必须发生在scope.$apply方法中才会被观察到。Angular框架封装了$apply过程,无需我们操心。

  4、更新: AngularJS通过在顶层 $scope对象执行事件循环,每个自作用域都会执行自己的脏值检测($digest),每个监控函数会检查变化,如果检测到变化,则 $scope对象触发指定的回调函数

  5、销毁: 当不再需要子作用域时,$socpe上可以通过使用 $destoy()方法销毁作用域,回收资源。

推荐阅读