说说AngularJS中的继承机制
发布在用Angular开发web应用2014年3月1日view:20107
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

enter image description here AngularJS中没有提供内建的用于继承的特性,在本文中,我们将一起来学习如何在AngularJS组件中使用普通的JavaScript继承模式。

控制器继承

首先,我们来谈谈控制器。实际上控制不太可能从父控制器中进行继承。这是因为子控制器的作用域将会原型继承父控制器的作用域。因此当你需要重用来自父控制器中的功能时,你所要做的就是在父作用域中添加相应的方法。这样一来,自控制器将会通过它的作用域的原型来获取父作用域中的所有方法。例如:

myModule.controller('ParentCtrl',function($scope){
    $scope.parentMethod = function(){
    //...
    }; 
});  

myModule.controller('ChildCtrl',function($scope){
    $scope.parentMethod();//这样就可以运行
});  

当然,这样的继承方式创造了非常强的耦合但是仅仅是单方向的耦合,因此你不能从你的父控制器中调用子控制器中的方法。对于这种情况,你需要使用事件分发:

myModule.controller('ParentCtrl',function($scope){
    $scope.$broadcast('event',args);
    $scope.$on('event-response',function (result){
    });
});   

myModule.controller('ChildCtrl',function($scope){
    $scope.$on('event',function (args){
        var result;
        //...
        $scope.$emit('event-response',result);
    });
});   

上面的代码仅作为参考使用,如果你需要从父控制器中调用子控制器的方法,那么使用上面的代码可能会发生错误。

假设现在你有两个页面,它们的大部分功能都相同,其中完全相同的功能超过50%。两个页面的视图完全不同但是可能视图后面的逻辑非常相似。在这种情形中你可以创建一个基本的控制器来封装基本的逻辑,然后再创建两个自控制器来继承它。基本控制器并不需要作为一个AngularJS控制器组件来实现,你完全可以将它创建为一个构造器函数:

function BaseCtrl($scope,$location,...){
    $scope.commonScopeMethod = function(){
        //...
    };
    $scope.commonVar = 42;
}
BaseCtrl.prototype.commonMethod1 = function(){
  //...
};
BaseCtrl.prototype.commonMethod2 = function(){
    //...
};  

现在子控制器可以轻松地从基本控制器中继承方法和属性:

function ChildCtrl($scope,$location,...){
    BaseCtrl.call(this,$scope,$location,...);
    $scope.childScopeMethod = function(){
    };
}

ChildCtrl1.prototype = Object.create(BaseCtrl.prototype);   

ChildCtrl1.prototype.chidMethod1 = function(){
    this.commonMethod1();
};

myModule.controller('ChildCtrl1',ChildCtrl1);  

在这里我们使用了经典的继承模式。我们也可以使用同同样的方法来创造第二个子控制器。

Service继承

正如你所了解的我们有两种方式来创建可注入(通过依赖注入)的AngularJS service:

  • module.factory(name,factoryFn)
  • module.service(name,factoryFn)

module.factory

在module.factory中factoryFn返回一个对象字面量,它是真正的service。幕后ANgularJS会在injector内部调用factory函数。

如果我们需要在由module.factory实例化的services之间进行继承,由Object.create进行的原型继承就合适。

我们先来创建基本service:

var BaseService = (function(){
    var privateVar = 0;
    return {
        someAwesomeStuff: function(){
            if(privateVar === 42){
                alert('You reached the answer!');
            }
            privateVar += 1;
        };
    };
})();   

现在这里有一个子service:

var ChildService = Object.create(BaseService);   
ChildService.someMoreAwesomeStuff = function(){
    //...
};   

module.factory('ChildService',function(){
    return ChildService;
});

现在你可以在不同的组件中注入ChildService,并重用继承自BaseService的方法。

function MyCtrl(ChildService){
    ChildService.someAwesomeStuff();
}   

moudle.service

既然我们有了factory为什么还需要service呢?假设我是一个迷糊的开发者,我并不理解原型继承的真正威力但是我想对我的模型使用经典的样式。通过使用它我们就可以创建一系列构造器函数来很好的控制我们的模型。

下面是一个我们对module.service使用原型继承模式的例子:

function Human(name){
    this.name = name;
}
Human.prototype.talk = function(){
    return 'My name is ' + this.name; 
}   
Human.$inject = ['name'];   

function Superhero = function(name abilities){
    Human.call(this,name);
    this.abilities = abilities;
}

Superhero.prototype = Object.create(Human.prototype);
Superhero.prototype.saveTheWorld = function(){
    return 'Saving the world with ' + this.abilities.join(', ');
};
Super.$inject = ['name','AbilitiesCollection'];  

angular.module('demo').service('Human',Human);
angular.module('demo').service('Superhero',Superhero);
angular.module('demo').value('name','Super Dev');
angular.module('demo').value('AbilitiesCollection',['C++','JavaScript']);   

本文译自Inheritance in AngularJS,原文地址http://blog.mgechev.com/2013/12/18/inheritance-services-controllers-in-angularjs/

如果你觉得本文对你有帮助,请点击为我提供赞助

评论
发表评论
2年前
添加了一枚【评注】:asdfadsf
2年前
添加了一枚【评注】:两个不同的controller 直接可以通过 $scope 取对方的方法? 明显不科学
4年前
添加了一枚【评注】:这样添加的Factory怎么实现注入呢?
WRITTEN BY
张小俊128
Intern in Baidu mobile search department。认真工作,努力钻研,期待未来更多可能。
TA的新浪微博
PUBLISHED IN
用Angular开发web应用

讲述Angular开发框架的基础知识,帮助读者快速学习并深入理解Angular的开发理念和具体应用方式

我的收藏