在Angular中创建一个对象时,需要依赖另一个对象,这是代码层的一种依赖关系,当这种依赖被声明后,Angular通过injector注入器将所依赖的对象进行注入操作。

一、依赖注入的原理

看下面的示例代码:

 <div ng-controller="MyController">
<div class="{{cls}}">{{show}}</div>
<button ng-click="onClick()">点我</button>
</div>
 var myapp = angular.module('MyApp', []);
myapp.config(function($controllerProvider) {
$controllerProvider.register('MyController', ['$scope', function($scope) {
$scope.cls = '';
$scope.onClick = function () {
$scope.cls = 'show';
$scope.show = '点击后显示的内容';
};
}]);
});

看上面的代码,与我们平时定义控制器的方式不一样

 myapp.controller('MyController', ['$scope', function($scope){
// 控制器代码
}]);

在Angular中,通过模块的config函数来声明需要注入的依赖对象,而声明的方式是通过调用provider服务。

但在Angular内部,控制器并不是由provider服务来创建的,而是由controllerProvider服务创建,在创建过程中,实际上是在config函数中调用controllerProvider服务的register方法,再调用injector注入器完成各个依赖对象的注入。
 
 
 
 

二、简单依赖注入的示例

在Angular中,config函数的功能是为定义的模板对象注入依赖的各种服务。除了用于注册控制器的controllerProvider服务外,还有一个$provide服务,其中它包含了如provider方法、factory方法、service方法和value方法,这些方法都可以通过服务创建一个自定义的依赖注入对象。

示例:

 <div ng-controller="myCtrl">
<div class="{{cls}}">{{text}}</div>
<button ng-click="onClick(1)">早上</button>
<button ng-click="onClick(2)">上午</button>
<button ng-click="onClick(3)">下午</button>
<button ng-click="onClick(4)">晚上</button>
</div>
 var app = angular.module('myApp', []);
app.config(function ($provide) {
$provide.provider('myprovider', function () {
this.$get = function () {
return {
val: function (name) {
return name;
}
}
}
})
});
app.config(function ($provide) {
$provide.factory('myfactory', function () {
return {
val: function (name) {
return name;
}
}
})
});
app.config(function ($provide) {
$provide.value('myvalue', function (name) {
return name;
})
});
app.config(function ($provide) {
$provide.service('myservice', function () {
return {
val: function (name) {
return name;
}
}
})
});
app.controller('myCtrl', ['$scope', 'myprovider', 'myfactory', 'myvalue', 'myservice',
function ($scope, myprovider, myfactory, myvalue, myservice) {
$scope.cls = '';
$scope.onClick = function (t) {
$scope.cls = 'show';
switch (t) {
case 1: $scope.text = myprovider.val('早上好'); break;
case 2: $scope.text = myfactory.val('上午好'); break;
case 3: $scope.text = myvalue('下午好'); break;
case 4: $scope.text = myservice.val('晚上好'); break;
}
}
}]);

三、依赖注入标记

每个Angular应用都是通过由注入器(injector)负责查找和创建依赖注入的服务,当注入器执行时,它需要一些标记,来判断需要注入什么样的依赖服务,而这些标记,就是依赖注入标记。

依赖注入标记根据声明的方式,分为:

  ——推断式注入

  ——标记式注入

  ——行内式注入

1.推断式注入

推断式注入是一种猜测式的注入,在没有明确声明的情况下,Angular认为参数名称就是依赖注入的函数名,并在内部调用函数对象的toString方法,获取对应的参数列表,然后通过注入器(injector)将这些参数注入到应用实例中,从而实现依赖注入。

示例:

 <div ng-controller="myCtrl">
<input type="button" value="弹出对话框" ng-click="onClick('我是一个弹出对话框')">
</div>
 var app = angular.module('myApp', []);
app.factory('myfactory', function ($window) {
return {
show: function (text) {
$window.alert(text);
}
}
});
var myCtrl = function ($scope, myfactory) {
$scope.onClick = function (msg) {
myfactory.show(msg);
}
};
app.controller('myCtrl', myCtrl);

2.标记式注入

标记式注入明确了一个函数在执行过程中需要依赖的各项服务,它可以直接调用$injector属性来完成,它的属性值是一个数组,数组元素是需要注入的各项服务的名称,所以这种方式的注入顺序很重要。

示例:

 <div ng-controller="myCtrl">
<div class="show">{{text}}</div>
<input type="button" value="弹出" ng-click="onShow('我是一个弹出对话框')">
<input type="button" value="显示" ng-click="onWrite('今天天气有点冷啊')">
</div>
 var app = angular.module('myApp', []);
app.factory('$show', ['$window', function ($window) {
return {
show: function (text) {
$window.alert(text);
}
}
}]);
app.factory('$write', function () {
return {
write: function (text) {
return text;
}
}
}); var myCtrl = function ($scope, $show, $write) {
$scope.onShow = function (msg) {
$show.show(msg);
}
$scope.onWrite = function (msg) {
$scope.text = $write.write(msg);
}
};
app.controller('myCtrl', myCtrl);
myCtrl.$inject = ['$scope', '$show', '$write'];

这种注入方式由于服务名和函数参数名在名称和顺序的一一对应关系,使得服务名和函数体绑定在一起,因此这种方式可以在压缩或混淆后的代码中执行。

3.行内式注入

所谓行内式注入,就是在构建一个Angular对象时,允许将一个字符型数组作为对象的参数,而不仅仅是一个函数。

在这个数组中,除最后一个必须是函数体外,其余都代表注入对象中的服务名,而他们的名称和顺序与最后一个函数的参数是一一对应的。

示例:

 <div ng-controller="myCtrl">
<div class="show">{{text}}</div>
<input type="button" value="求和" ng-click="onClick(5,10)">
</div>
 var app = angular.module('myApp', []);
app.factory('$sum', function () {
return {
add: function (m, n) {
return m + n;
}
}
});
app.controller('myCtrl', ['$scope', '$sum', function ($scope, $sum) {
$scope.onClick = function (m, n) {
$scope.text = m + " + " + n + ' = ' + $sum.add(m, n);
}
}]);

这种方法更简洁,同样也能在压缩或混淆后的代码中执行。

四、$injector常用API

Angular中依赖注入离不开一个重要的对象--注入器($injector),整个Angular应用中的注入对象都由它负责定位和创建,它也有很多方法,如gethasinvoke等。

1.has和get方法

has方法的功能是根据传入的名称,从注册的列表中查找对应的服务,如果找到返回true,否则返回false。

 injector.has(name)
// injector为获取的$injector对象
// name为需要查找的服务名称

get方法返回指定名称的服务实例,获取到服务的实例对象后,就可以直接调用服务中的属性和方法。

 injector.get(name)
// injector为获取的$injector对象
// name为需要返回实例的服务名称

示例:

 var app = angular.module('myApp', []);
app.factory('$custom', function () {
return {
print: function (msg) {
console.log(msg);
}
}
});
// 获取injector对象
var injector = angular.injector(['app', 'ng']);
// 通过has方法判断是否有$custom服务
var has = injector.has('$custom');
console.log(has);
// 判断如果存在$custom服务,则调用其方法在控制台输出任意字符
if (has) {
var custom = injector.get('$custom');
custom.print('控制台输入任意的内容!');
}
app.controller('myCtrl', ['$scope', '$custom', function ($scope, $custom) {
// ....
}]);

2.invoke方法

invoke方法可以执行一个自定义的函数,除此之外,在执行函数时,还能传递变量给函数自身。

 injector.invoke(fn, [self], [locals])
// injector为获取的$injector对象
// fn为需要执行的函数名称
// self是可选参数,它是一个对象,表示用于函数中的this变量
// locals可选参数,也是一个对象,它能为函数中的变量名的传递提供方法支持

示例:

 var myapp = angular.module('myApp', []);
myapp.factory('$custom', function () {
return {
print: function (msg) {
console.log(msg);
}
}
});
var injector = angular.injector(['myapp', 'ng']);
var fun = function ($custom) {
$custom.print('函数执行成功!');
}
injector.invoke(fun);
myapp.controller('myCtrl', ['$scope', '$custom', function ($scope, $custom) {
//...
}]);

依赖注入——angular的更多相关文章

  1. angular 依赖注入

    依赖注入    依赖注入(DI)是一个经典的设计模式, 主要是用来处理组件如何获得依赖的问题.关于DI,推荐阅读Martin Flower的文章(http://martinfowler.com/art ...

  2. Angular4学习笔记(四)- 依赖注入

    概念 依赖注入是一种设计思想,并不是某一类语言所特有的,因此可以参考开涛大神关于学习Java语言的Spring框架时对其的解释: DI-Dependency Injection,即"依赖注入 ...

  3. Angular依赖注入详解

    Angular算是将后端开发工程化引入前端的先驱之一,而Dependency injection依赖注入(后面简称为DI)又是Angular内部运作的核心功能,所以要深入理解Angular有必要先理解 ...

  4. 30行代码让你理解angular依赖注入:angular 依赖注入原理

    依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...

  5. angular中自定义依赖注入的方法和decorator修饰

    自定义依赖注入的方法 1.factory('name',function () { return function(){ } }); 2.provider('name',function(){ thi ...

  6. angular 依赖注入原理

    依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...

  7. angular路由 模块 依赖注入

    1.模块 var helloModule=angular.module('helloAngular',[]); helloModule.controller('helloNgCrtl',['$scop ...

  8. angular源码阅读3:真的,依赖注入的原理

    前面已经提到了: 如何注册一个module. 如何获取一个module. injector与module以及provider的关系. 那么已经剩下最后一部分了,就是关于依赖是如何被注入的. 且看下面这 ...

  9. angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。

    最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...

随机推荐

  1. zencart网站上线前,邮件模板默认网址修改

    涉及到的文件 includes\languages\语言包\模板\email_extras.php 后台\includes\languages\语言包\email_extras.php 后台\incl ...

  2. java 学习笔记(四) java连接ZooKeeper

    public class Demo2 { public static void main(String[] args) { String connectString = "192.168.1 ...

  3. JavaScript 函数调用时带括号和不带括号的区别

    function countBodyChildren(){ var body_element = document.getElementsByTagName("body")[0]; ...

  4. java文件断点续传上传下载解决方案

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  5. 使用svn在github上下载文件夹

    今天想在github上下载mybatis-generator的eclipse插件,可是如何在github上下载一个文件夹而不用把这个项目clone呢,搜了一下,发现可以直接用svn来下载 只需将将路径 ...

  6. python实现一个朴素贝叶斯分类方法

    1.公式 上式中左边D是需要预测的测试数据属性,h是需要预测的类:右边式子分子是属性的条件概率和类别的先验概率,可以从统计训练数据中得到,分母对于所有实例都一样,可以不考虑,所有只需 ,返回最大概率的 ...

  7. 文章翻译:ABP如何在EF core中添加数据过滤器

    原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-cor ...

  8. 51nod-1640--天气晴朗的魔法(简单最小生成树)

    1640 天气晴朗的魔法 题目来源: 原创 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 这样阴沉的天气持续下去,我们不免担心起他的健康. 51nod魔法学校近日 ...

  9. JS框架_(Bootstrap.js)实现简单的轮播图

    Bootstrap框架中 轮播(Carousel)插件是一种灵活的响应式的向站点添加滑块的方式 轮播图效果: <!DOCTYPE html> <html> <head&g ...

  10. 数据预测算法-ARIMA预测

    简介 ARIMA: AutoRegressive Integrated Moving Average ARIMA是两个算法的结合:AR和MA.其公式如下: 是白噪声,均值为0, C是常数. ARIMA ...