JavaScript模块化开发一瞥

上传人:飞*** 文档编号:4678951 上传时间:2017-08-21 格式:DOC 页数:5 大小:39KB
返回 下载 相关 举报
JavaScript模块化开发一瞥_第1页
第1页 / 共5页
JavaScript模块化开发一瞥_第2页
第2页 / 共5页
JavaScript模块化开发一瞥_第3页
第3页 / 共5页
JavaScript模块化开发一瞥_第4页
第4页 / 共5页
JavaScript模块化开发一瞥_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《JavaScript模块化开发一瞥》由会员分享,可在线阅读,更多相关《JavaScript模块化开发一瞥(5页珍藏版)》请在金锄头文库上搜索。

1、对于那些初学 JavaScript、同时又正用它构建大型应用程序的开发者而言,必须面对的首要挑战是,该如何组织代码。尽管起初通过在标记之间嵌入数百行代码就能跑起来,不过很快代码会变得一塌糊涂。其中的难点在于,对于组织我们的代码,JavaScript 并未提供任何明显帮助。从字面上看,C#有 using,Java 有 import而JavaScript 一无所有。这就迫使 JavaScript 作者去尝试各种不同约定(conventions),并用我们拥有的这种语言创建了一些实践方法来组织大型 JavaScript 应用程序。形成现代 JavaScript 基础的那些模式、工具及实践必将来自语言

2、本身以外的实现 Rebecca Murphy模块模式(The Module Pattern)解决此问题使用最为广泛的方法是模块模式(Module Pattern)。我尝试在下面解释一个基本示例,并谈论它的一些属性。对于各种不同方法更好的描述和梦幻般的运行,请参阅 Ben Cherry 的帖子 JavaScript Module Pattern: In-Depth(深入理解JavaScript 模块模式)。(function(lab49) function privateAdder(n1, n2) return n1 + n2;lab49.add = function(n1, n2) retur

3、n privateAdder(n1, n2); / 原文代码有误,已修正。;)(window.lab49 = window.lab49 | );上面的示例中,我们只使用一些来自语言本身的基本功能,就创建了曾在 C#和 Java等语言中见过的类似结构。隔离(Isolation)你会注意到这段代码包在一个立即调用的函数里(查看最后一行)。在浏览器中,默认情况下会在全局范围(global scope)级别上对 JavaScript 文件进行评估(evaluated),因此在我们在文件内声明的任何内容都是随处可用的。想象一下,如果在 lib1.js 中有句 var name = .,而 lib2.js

4、 中有另一句 var name = .。那么第二个 var 语句会替掉第一句的值这可不太妙。然而,由于 JavaScript 拥有函数作用域(function scoping)级别,上例中所声明的一切都在该函数自身作用域中,与全局作用域相脱离。这意味着,无论未来在系统中发生什么,位于该函数中的任何内容都会被隔离开来。命名空间(Namespacing)在最后一行中,你会发现我们要么把 window.lab49 赋给其自身,要么把空对象直接量(empty object literal)赋给它。尽管看起来有些奇怪,但是让我们一起看下某个虚构的系统,在那里我们拥有若干 js 文件,所有文件都用了上例中

5、的函数包装器( function wrapper)。首个包含进来的文件会评估 OR(逻辑或)语句,并发现左侧表达式为undefined(未定义)。由于 undefined 是虚假值(falsely value),因此 OR 语句会继续评估右侧表达式,本例中是个空对象直接量。此 OR 语句实际上是个会返回评估结果的表达式,然后将结果赋给全局变量 window.lab49。现在,轮到下个文件来使用此模式了,它会获得 OR 语句,并发现 window.lab49 当前是对象实例 真值( truthy value)。OR 语句会短路并返回这个值,并将此值立即赋给其自身 实际上啥也没做。这导致的结果是,

6、首个包含进来的文件会创建我们的 lab49 命名空间(只是个JavaScript 对象),而且每个使用这种结构的后续文件都只不过是重用这个现有实例。私有状态(Private State)正如我们刚才所说,由于位于函数内部,在其内部声明的一切内容都是处于该函数的范围内,而不是全局范围。对于隔离我们的代码这真太棒了,此外,它还有个影响是,没有人能调用它。中看不中用。刚刚我们还谈到,我们创建了 window.lab49 对象来有效管地理我们内容的命名空间。而且这个 lab49 变量是全局可用的,因为它被附加到 window 对象上。要想把我们模块中的内容暴露给外部,你可以公开地说,我们要做的就是把一

7、些值附加到全局变量上。正如我们在上例中对 add 函数所做的一样。现在,在我们的模块外部可以通过 lab49.add(2, 2)来调用我们的 add 函数了。在此函数内声明我们的值的另一结果是,如果某个值不是通过将其附加到我们的全局命名空间或者模块外部的某物的方法来显示公开的,那么外部代码将无法碰到它。事实上,我们刚刚就创建了一些私有值。CommonJS 模块(CommonJS Modules)CommonJS 是一个主要由服务端 JavaScript 运行库(server-side JavaScript runtimes)作者组成的小组,他们一直致力于暴露及访问模块的标准化工作(standa

8、rdize exposing and accessing modules)。值得注意的是,尽管他们提议的模块系统不是来自于创建 JavaScript 标准同一小组的一个标准,因此它更多地成为JavaScript 运行库作者之间的非正式约定(informal convention)。我通常支持 CommonJS 的想法,但要搞清楚的是:它并不是一份崇高而神圣的规范(就像 ES5 一样);它不过是某些人在邮件列表中所讨论的想法。而且这些想法多数都没有付诸实现。 Ryan Dahl, node.js 的创造者该模块规范( Modules specification)的核心可谓开门见山。模块(Modu

9、les)在它们自己的上下文中进行评估,并且拥有全局变量 exports 以供模块使用。变量exports 只是个普通的 JavaScript 对象(plain old JavaScript object),甚至你也可以往它上面附加内容,与我们上面展示的命名空间对象类似。为了访问某个模块,你要调用全局函数 require,并指明你请求的包的标示符(identifier for the package)。然后评估该模块,并且无论返回什么都会附加到 exports 上。此模块将会缓存起来,以便后来的 require 函数调用来使用。/ calculator.jsexports.add = funct

10、ion(n1, n2) ;/ app.jsvar calculator = require(./calculator);calculator.add(2, 2);如果你曾经玩过 Node.js,那么你会发现上面的代码很熟悉。这种用 Node 来实现CommonJS 模块的方式是出奇地简单,在 node-inspector(一款 Node 调试器)中查看某个模块时将显示其包装在某个函数内部的内容,此函数正是传递给 exports 和require 的值。非常类似于我们上面展示的手攒模块。有几个 node 项目(Stitch 和 Browserify),它们将 CommonJS 模块带进了浏览器。

11、服务器端组件将这些彼此独立的模块 js 文件塞进一个单独的 js 文件中,并在那些代码外面包上生成的模块包装器(generated module wrapper)。CommonJS 主要设计用于服务端 JavaScript 运行库,而且由于有几个属性使得它们很难在浏览器中进行客户端代码的组织。 require 必须立即返回当你已经拥有所有内容时这会工作得非常好,但是当使用脚本加载器(script loader)异步下载脚本时就会有困难。 每个文件一个模块为了合并为 CommonJS 模块,必须把它们包裹到一个函数中,然后再组织为某种式样。如果没有某些服务器组件,正如上面提到的那些,就会让它们难

12、以使用,并且在许多环境(ASP.NET ,Java)下这些服务器组件尚不存在。异步模块定义(Asynchronous Module Definition)异步模块定义(Asynchronous Module Definition,通常称为 AMD)已设计为适合于浏览器的模块格式。它最初只是一个来自 CommonJS 小组的提议,但此后移到了GitHub 上,而且现在伴有一个适用于模块系统作者的测试套件,以便验证对于 AMD API的遵从性(compliance)。AMD 的核心是 define 函数。调用 define 函数最常见的方式是接受三个参数模块名(也就是说不再与文件名绑定)、该模块依

13、赖的模块标识符数组、以及工厂函数,它将返回该模块的定义。(还有其他的方式调用 define 函数详细信息参阅 AMD wiki)。define(calculator, adder, function(adder) return add: function(n1, n2) return adder.add(n1, n2););由于此模块的定义包在 define 函数的调用中,因此这就意味着,你可以愉快地在单个 js 文件内拥有多个模块。此外,由于当调用 define 模块工厂函数时,模块加载器拥有控制权,因此它可在闲暇之余解决(模块之间的)依赖关系如果那些模块必须首先异步下载,那就会很方便了。为

14、了与原本的 CommonJS 模块提议保持兼容已作出重大努力。当在模块工厂函数中使用 require 和 exports 时会有特殊处理,这意味着,那些传统的 CommonJS 模块可直接拿来用。看起来 AMD 正在成为颇受欢迎的组织客户端 JavaScript 应用程序的方式。无论是否通过如 RequireJS 或 curl.js、或是像 Dojo 等最近已采用 AMD 的 JavaScript 应用程序等模块资源加载器来组织代码。这是否意味着 JavaScript 很烂?(Does this mean JavaScript sucks?)缺乏将代码组织到模块中的语言级别的结构(langua

15、ge level constructs),这可能会让来自于其他语言的开发者感觉很不爽。然而,正由于此缺陷才迫使 JavaScript 开发者想出他们自己的模块构造模式,我们已经能够随着 JavaScript 应用程序的发展进行迭代和改进。欲深入了解此主题请访问 Tagneto 的博客。想象一下,即使这种功能类型(即 Module)在 10 年前就已包括在语言中。那么他们也不可能想到在服务器上运行大型 JavaScript 应用程序、在浏览器中异步加载资源、或者像文本模板(text templates)(那些载入器就像 RequireJS 所做的一样)那样包含资源等诸如此类的需求。正在考虑将模块(Modules)作为 Harmony/ECMAScript 6 的语言级别功能。这多亏了模块系统作者们的思想和过去几年的辛勤工作,很可能我们最终得到的语言会适用于构建现代 JavaScript 应用程序。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 研究报告 > 综合/其它

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号