本文共 4202 字,大约阅读时间需要 14 分钟。
函数是一个对象:它创建了范围
这是因为现在你已经把isDoingWork这个变量创建在了一个函数里面 -- 也就是我们们的匿名 IIFE 中 -- 而如此这个变量就只能通过这个函数才能访问到. 有趣的是Javascript中的所有函数都是第一类对象. 那很简明的意味着函数是一个对象,它可能通过一个变量被访问到. 或者说,另外一种描述的方式是你存储了指向 函数的一个引用,并在稍后的某个时间获取其变量.
在我们第一个示例中,我们的问题是并没有保存一个指向我们匿名函数的引用,所以我们永远也不能再获取到isDoingWork这个值。这就是我们下一个示例要改进的地方.
函数是一个对象 : 使用this
因为每一个函数都是一个对象,所以每个函数都会有一个this变量,这个变量向开发者提供了指向当前对象的引用. 为了提供在从外部大我们的函数及其范围的访问,我们可以返回这个this变量 -- 而它将会提供一个指向当前对象的引用.
然后,除非我们将这个私有的isDoingWork变量添加到函数引用(this)上,我们也不能够引用这个变量。为此我们要对之前的示例做一下轻微的改动。它看起来会像下面这样:
thing = (function(){ // 1. this.isDoingWork = false; // 2. console.log("isDoingWork value : " + isDoingWork); return this; // 3.}());
你可以看到第一行我们加入了一个新的全局变量thing,它包含了从匿名函数返回的值。从示例代码的开头跳到第三行,你可以看到我们返回了this变量。那就意味着我们返回了一个指向匿名函数的引用.
在第二行我们也已经将isDoingWork加入了this引用中,那样我们就可以使用语法thing.isDoingWork来从外部引用到这个值了.
自己动手看看
为了看看的运行,你可以做下面这几步:
1.下载本文的示例代码.
2.在你的浏览器中打开 modulePattern4.htm.
3.打开浏览器开发工具 -- F12(Chrome, IE) 或者 Ctrl-Shift-I (Opera) -- (那样你就可以看到控制台了)
4.你将会看到isDoingWork的值会输出到控制台,就像最开始那个示例中你看到的那样.
5.不过,现在你得输入thing.isDoingWork才能或者这个值.
模块模式总结
在最后这个示例中,变量值被成功的封装了,而其他的JavaScript库则可以明确的引用thing对象来获取这个值. 好像不大可能,而这帮助了我们保持全局命名空间的干净,并且在看起看来是更好的代码组织形式. 这也使得我们代码的维护更容易.
最终,我们用上了 AngularJS
因为使用模块模式是一个最佳实践,AngularJS的开发者就将一个模块系统构建到了库中.
Plunker 代码
首先你可以通过到这个Plunker上 ( - 在一个新的窗口或Tab页打开)获取整个AngularJS示例.
而我们在这里展示出代码,那样我们就可以更方便的谈论它了.
首先,让我们看看这个 HTML.
Angular Module Example mc refers to MainCtrl which has been added to the angular app module
Hello {
{mc.name}}!
- { {a}}
Hello {
{sc.name}}
- { {a}}
Angular 指令 : ng-app
Angular 所定义和使用的东西叫做指令。这些指令基本上就是由Angular定义属性,而AngularJS编译器(Angular的JavaScript)会将它们转换成其他的东西.
我们应用了ng-app指令,为我们的Angular应用定义了一个名称,叫做mainApp.
mainApp 就是我们稍后会看到的模块模式的起点.
被引入的脚本 : 每个都是一个模块
现在,请注意有三个脚本被引入到了这个HTML中.
第一个是必须的AngularJS库.
而其他两个则是作为模块被实现的Angular控制器.
它们被作为模块实现以保持代码彼此,还有从这个应用上看,都是独立的.
AngularJS : 创建 score
在往下看,你将会看到两个以如下代码开头的div:
这是在为div的每一个都设置上ng-controller. 这些div中的每一个都有其各自的范围. 第一个控制器的名字叫做 MainCtrl,第二个叫做 SecondCtrl.
AngularJS 编译器会在你提供(引入)的代码中用这两个名称查找对应的函数.
如果AngularJS编译器没有找个这两个名称对应的函数,它就会抛出一个错误.
mainCtrl.js : 第一个控制器
让我们来看看mainCtrl.js文件里面有些啥东西.
你可以在Plunker页面的左侧点击它在Plunker中将其打开.
当你打开了它,你将会看到一些看上去很熟悉的代码。好吧,你至少会看出来它们都是被包在一个IIFE中的.
(function() { var app = angular.module('mainApp', []); app.controller('MainCtrl', function() { console.log("in MainCtrl..."); // vt = virtual this - just shorthand vt = this; vt.name = 'MainCtrl'; vt.allThings = ["first", "second", "third"]; });})();
那是因为我们需要这些代码在文件mainCtrl.js被加载时就运行.
现在,请注意在这个IIFE中的第一行代码.
var app = angular.module('mainApp', []);
这行代码是Angular将一个模块添加到其命名空间的方式. 在这里,我们添加了一个将用来展示我们应用程序的模块. 这是应用程序的模块,而我们已经将其命名为 itmainApp, 它跟HTML页面上ng-app所指定的值是一样的.
我们也创建了一个叫做app的(只在IIFE本地可见的)本地变量,以便我们将可以在这个函数内部用来再次添加一个控制器.
奇怪的 Angular 语法
请你也要再仔细看看第一行。你会注意到我们是首次创建mainApp模块,而如果是首次,则我们必须提供以字符串数组的形式提供其可能需要的任何依赖(,表示出依赖库的名称). 不过,在这里对于这个简单的示例而言,我们不需要任何的依赖。但Angular仍然需要我们传入一个空的数组,以便它知晓我们正在创建新的模块,而不是去试图加载一个已经被创建好了的模块.
提示: 你将会看到我们会在secondCtrl.js里加载mainApp模块,而上面所提的数组将会有更多的作用.
我们一把mainApp创建好,就需要向其添加我们的控制器. 这些就是Angular预期我们在HTML(的div中)加入的控制器.
将控制器添加到App模块
添加控制器的代码看起来像下面这样:
app.controller('MainCtrl', function() { console.log("in MainCtrl..."); // vt = virtual this - just shorthand vt = this; vt.name = 'MainCtrl'; vt.allThings = ["first", "second", "third"]; });
为了添加我们的控制器函数,我们向app.controller()函数提供了一个控制器名称和一个函数. 在此处我们提供了一个匿名函数.
所以,我们的控制器主体代码就是下面这几行了:
console.log("in MainCtrl..."); // vt = virtual this - just shorthand vt = this; vt.name = 'MainCtrl'; vt.allThings = ["first", "second", "third"];
这里,当我们的控制器运行时,会向控制台输出一行. 然后,我们将this变量重命名为vt(方便起见,就叫他虚拟的this) ,而后我天为其添加了一个name属性和一个叫做allThings 的字符串数组.
控制器和封装
那就是当控制器被Angular调用时会运行的代码. 那个控制器会在文件被加载时运行起来,也就是一开始HTML被加载的时候. 这意味着控制器会被加载到app模块中,而这些属性会被添加到控制器对象(函数)中。因为我们想this变量添加了属性,我们就可以在稍后获取这些属性,但它们是被封装了起来的,因此它们不可以被每个人随意的更改.
现在,让我们跳到HTML中控制器被引用和使用的地方.
第一个Div
这是我们的MainCtrl控制器被引用和使用的第一个Div。它看起来就像下面这样:
mc refers to MainCtrl which has been added to the angular app module
Hello {
{mc.name}}!
- { {a}}
这个div输出我们的web页面的如下部分,看起来就是接下来这张图片上所展示的那样.
转载地址:http://tdytx.baihongyu.com/