杀手锏 - 在控制器中显式地声明数据模型

在这篇文章中,我们将会研究一下,在控制器中显式地声明数据模型对我们的编程都有哪些好处,在这个过程中有哪些需要我们注意的地方;好了,废话不多说,进入主题吧!

需要知道的知识

ng-controller 是一个特殊的指令,它会以父级作用域(一般为$rootScope或者另外一个ng-controller的作用域)为原型生成一个子作用域;这种继承的机制可以创建一个隔离层,用来将需要协同工作的方法和数据模型对象放置在一起。

JavaScript 的对象,要么是值复制要么是引用复制。字符串,数字,布尔型变量都是值复制;数组,对象,函数都是引用复制。

在控制器中使用裸值

在控制器中,我们不推荐使用裸值形式为一个变量赋值,但是为了说明这个问题,我们尝试使用这种方法去编写我们的程序。

我们创建两个控制器,一个父控制器,一个子控制器;在父控制器和子控制器中分别使用父控制器中的数据,然后在父控制器和子控制器中分别修改我们使用的数据,看看会发生什么?

代码如下所示

HTML代码:

html<div ng-app="MyApp">
    <div ng-controller="ParentController">
        <h3>Parent Section: {{name}}</h3><br/>
        <button ng-click="parentChangeName()">parentChangeName</button>
        <div ng-controller="ChildController">
            <h3>Child Section: {{name}}</h3><br/>
            <button ng-click="childChangeName()">childChangeName</button>
        </div>
    </div>
</div>

JS代码:

javascriptangular.module("MyApp", [])
.controller("ParentController", function($scope){
    $scope.name = "dreamapple";
    $scope.parentChangeName = function(){
        $scope.name = "parent dreamapple";
    }
})
.controller("ChildController", function($scope){
    $scope.childChangeName = function(){
        $scope.name = "child dreamapple";
    }
});

Online Code Part1

关于上面的代码,我们还是要好好地分析一下:

首先它的表现结果是这样的:
(1)假如我们刚开始点击的是parentChangeName按钮,那么,父控制器和子控制器的h3标签中的{{name}}值都将是parent dreamapple;然后我们点击childChangeName按钮,会发现,只有子控制器的h3标签中的{{name}}值发生了变化,变成了child dreamapple;父控制器里面的{{name}}没有发生变化。
(2)假如我们刚开始的时候先点击的是childChangeName按钮,那么结果与刚才的不一样,只有子控制器的h3标签中的{{name}}值发生了变化,变成了child dreamapple;父控制器里面的{{name}}没有发生变化。然后当我们点击parentChangeName按钮时也只有父控制器里面的{{name}}的值发生了变化。子控制器也没有发生变化。

因为是这样的,由于原型继承的关系,初始化状态下,我们的子控制器虽然有自己的作用域,但是里面的属性值和方法,与父控制器的是一样的;所以,在子控制器有任何操作之前,子控制器里面的属性值与父控制器里面是一样的,所以当点击parentChangeName按钮时,父控制器里面的属性值发生变化,所以子控制器里面的属性值也发生了变化。但是,当我们再次点击childChangeName按钮时,这时候子控制器因为有自己的作用域,所以只能够修改自己作用域里的属性值,无法修改父控制器作用域里面的属性值。

第二种情况也很好解释,因为一开始,点击childChangeName按钮就修改了子作用域的属性值,虽然我们紧接着点击了parentChangeName按钮但是却没有改变子作用域里面的属性值,因为点击parentChangeName按钮只能在初始化的时候(并且子作用域中没有对那个属性进行初始化Online Code Part2),改变父控制器和子控制器的属性值,如果子控制器里面的属性已经被修改或者初始化了,那么父控制器也不可以改变子控制器里面的属性值。

在控制器中显式声明数据模型

我们将修改上面的代码,不再使用裸值,而是显式的声明一个对象。

代码部分如下

HTML代码:

html<div ng-app="MyApp">
    <div ng-controller="ParentController">
        <h3>Parent Section: {{person.name}}</h3><br/>
        <button ng-click="parentChangeName()">parentChangeName</button>
        <div ng-controller="ChildController">
            <h3>Child Section: {{person.name}}</h3><br/>
            <button ng-click="childChangeName()">childChangeName</button>
        </div>
    </div>
</div>

JS代码:

javascriptangular.module("MyApp", [])
.controller("ParentController", function($scope){
    // $scope.name = "dreamapple";
    $scope.person = {
        name: "dreamapple"
    };
    $scope.parentChangeName = function(){
        // $scope.name = "parent dreamapple";
        $scope.person.name = "parent dreamapple";
    }
})
.controller("ChildController", function($scope){
    $scope.childChangeName = function(){
        // $scope.name = "child dreamapple";
        $scope.person.name = "child dreamapple";
    }
});

Online Code Part3

我们来看看它的表现结果:
这时你会发现,不论是点击parentChangeName按钮还是点击childChangeName按钮,父控制器和子控制器里面的{{name}}都会发生变化,这是为什么呢?
因为,首先我们在父作用域上创建了一个对象也就是一个数据模型,子控制器上也会有对这个对象的引用,所以无论我们改变哪一个控制器里这个对象的属性,都会反应到这两个控制器里面。

到这里,我想要和大家分享的差不多快结束了,不过还有一点需要注意的,就是使用任何会创建子作用域指令时,如果将指令定义中的scope设置为true,都会有上面的特性,我们可以根据自己的需要,采取不同的方法;好了,差不多该睡午觉了,还有,如果大家觉得我哪里说得不对,还望指出,我们一起进步。

    原文作者:dreamapplehappy
    原文地址: https://segmentfault.com/a/1190000002777963
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞