资讯专栏INFORMATION COLUMN

JavaScript模块化编程探索

jayzou / 964人阅读

摘要:模块化编程,已经成为一个迫切的需求。随着网站功能逐渐丰富,网页中的也变得越来越复杂和臃肿,原有通过标签来导入一个个的文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作模块复用单元测试等等一系列复杂的需求。

随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂。网页越来越像桌面程序,需要一个团队分工协作、进度管理、单元测试等等......开发者不得不使用软件工程的方法,管理网页的业务逻辑。
Javascript模块化编程,已经成为一个迫切的需求。

从CommonJS说起

CommonJS团队定义了module格式来解决JavaScript作用域问题,这样确保了每一个module都在自己的命名空间下执行。

根据CommonJS的规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

CommonJS给出2个工具来实现模块之间的依赖:

require() 用于在当前作用域引入已有的模块

module object 用于从当前作用域导出一些东东

那就先搞一个Hello world的小栗子来试下吧!

编写简单的JavaScript模块

新建一个项目文件夹吧,虽然项目很小。。。起名commonjs,在里边新建2个JavaScript文件,分别命名为world.js和salute.js,代码如下:

// salute.js 打招呼
var MySalute = "Hello";
module.exports = MySalute;

/*注意上下是分别写在2个文件js文件里哦*/

// world.js
var MySalute = require("./salute");
var Result = MySalute + " world!";
console.log(Result);

然后无知的我有新建了一个demo.html,(想要在浏览器里打开看看是什么样子)内容如下:




    
    Document
    


    

结果在浏览器中打开,查看控制台大失所望,报了一个错误
world.js:2 Uncaught ReferenceError: require is not defined
发现浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量:

module

exports

require

global
只要能够提供这四个变量,浏览器就能加载 CommonJS 模块,问题是可以解决的,但是好像并不怎么好玩,有兴趣的朋友可以去阮老师博客里逛逛啊传送门

现在我决定要去Node.js里边玩一下了

Node.js环境里玩一把

打开命令行工具cd到项目目录:

结果顺利打印出了Hello world!果然很有搞头啊,呵呵.

那么写到为止简单实现了模块之间的引用,到底这个CommonJS规范下还可以做些什么呢?到CommonJS官网看了一下,发现如下内容:

JavaScript是强调大面向对象语言,而且带有最快的解释器,而且之前的JavaScript定义的APIs仅仅用于构建浏览器端的应用,然而呢有了这个CommonJS就可以构建更宽范围的应用了,具体点就是可以用JavaScript来写:

服务器端应用Server-side JavaScript applications

命令行工具Command line tools

基于GUI的桌面应用Desktop GUI-based applications

Hybrid applications (Titanium, Adobe AIR)(这个是什么?虽然我现在还不知道,但感觉它很牛逼)

AMD是用来干甚么的?

AMD (Asynchronous Module Definition)肤浅的理解异步模块定义。。。
一开始大家可能以为CommonJS的天性就是同步,它的模块系统并不适用于浏览器,而这个AMD就是指定了一个标准,证明给别人看模块化的JavaScript可以异步加载依赖,解决同步加载出现的问题。

定义
define函数是AMD定义模块的方法:
define(id?: String, dependencies?: String[], factory: Function|Object);
id:指定模块名字
dependencies:指明依赖
factory:是定义模块的,可以是function或object,如果是function那么函数的返回值就是module 导出的值。
examples
define("myModule", ["jquery"], function($) {
    // $ is the export of the jquery module.
    $("body").text("hello world");
});
// and use it
require(["myModule"], function(myModule) {});
RequireJS

随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作、模块复用、单元测试等等一系列复杂的需求。
RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一。最新版本的RequireJS压缩后只有14K,堪称非常轻量。它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升。此段出处

对比js模块的同步加载和异步加载

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

浏览器同步加载js模块

新建a.js

(function(){
    function test(){
        alert("it works");
    }

    test();
})()

新建demo1.html




    
    Document
    


    body

在浏览器中运行demo1.html,alert执行的时候,html内容是一片空白的,即body并未被显示,当点击确定后,才出现,这就是JS阻塞浏览器渲染导致的结果。

RequireJS异步加载js模块

把a.js改写如下:

define(function(){
    function test(){
      alert("it works");
    }

    test();
})

到githug下载require.jsRequireJS download修改demo1.html如下:

!DOCTYPE html>


    
    Document
    
    


    body

浏览器提示了"it works",说明运行正确,但是有一点不一样,这次浏览器并不是一片空白,body已经出现在页面中,目前为止可以知道requirejs具有如下优点:

防止js加载阻塞页面渲染

管理模块之间的依赖性,便于代码的编写和维护,使得代码更加优雅。

CMD规范

CMD(Common Module Definition) 模块定义规范。该规范明确了模块的基本书写格式和基本交互规则。在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:

define(factory);

define 是一个全局函数,用来定义模块。define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。

factory 为对象、字符串时,表示模块的接口就是该对象、字符串。比如可以如下定义一个 JSON 数据模块:

define({ "foo": "bar" });

require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口。

define(function(require, exports) {

  // 获取模块 a 的接口
  var a = require("./a");

  // 调用模块 a 的方法
  a.doSomething();

});

require.async 方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。

define(function(require, exports, module) {

  // 异步加载一个模块,在加载完成时,执行回调
  require.async("./b", function(b) {
    b.doSomething();
  });

  // 异步加载多个模块,在加载完成时,执行回调
  require.async(["./c", "./d"], function(c, d) {
    c.doSomething();
    d.doSomething();
  });

});

require 是同步往下执行,require.async 则是异步回调执行。require.async 一般用来加载可延迟异步加载的模块。
更详细内容请查看CMD 模块定义规范

sea.js

RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。
在 SeaJS 中,所有 JavaScript 文件都应该用模块的形式来书写,并且一个文件只包含一个模块。
使用全局函数 define 来定义模块:

define(id?, dependencies?, factory);

id
当前模块的唯一标识。该参数可选。如果没有指定,默认为模块所在文件的访问路径。如果指定的话, 必须是顶级或绝对标识(不能是相对标识)。
dependencies
当前模块所依赖的模块,是一个由模块标识组成的数组。该参数可选。如果没有指定,模块加载器会从 factory.toString() 中解析出该数组。
factory
模块的工厂函数。模块初始化时,会调用且仅调用一次该工厂函数。factory 可以是函数, 也可以是对象、字符串等任意值,这时 module.exports 会直接设置为 factory 值。
factory 函数在调用时,会始终传入三个参数: require、exports 和 module, 这三个参数在所有模块代码里可用。

define(function(require, exports, module) {

  // The module code goes here
  
});

more

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82895.html

相关文章

  • 探索Javascript 异步编程

    摘要:因为浏览器环境里是单线程的,所以异步编程在前端领域尤为重要。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案函数体内外的数据交换和错误处理机制。 showImg(https://segmentfault.com/img/bVz9Cy); 在我们日常编码中,需要异步的场景很多,比如读取文件内容、获取远程数据、发送数据到服务端等。因为浏览器环境里Javascript是单线程的,...

    Salamander 评论0 收藏0
  • 前端阅读笔记 2016-11-25

    摘要:为了防止某些文档或脚本加载别的域下的未知内容,防止造成泄露隐私,破坏系统等行为发生。模式构建函数响应式前端架构过程中学到的经验模式的不同之处在于,它主要专注于恰当地实现应用程序状态突变。严重情况下,会造成恶意的流量劫持等问题。 今天是编辑周刊的日子。所以文章很多和周刊一样。微信不能发链接,点了也木有用,所以请记得阅读原文~ 发个动图娱乐下: 使用 SVG 动画制作游戏 使用 GASP ...

    KoreyLee 评论0 收藏0
  • 详解javascript的类

    摘要:原文地址详解的类博主博客地址的个人博客从当初的一个弹窗语言,一步步发展成为现在前后端通吃的庞然大物。那么,的类又该怎么定义呢在面向对象编程中,类是对象的模板,定义了同一组对象又称实例共有的属性和方法。这个等同于的属性现已弃用。。 前言 生活有度,人生添寿。 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客   Javascript从当初的一个弹窗语言,一...

    hufeng 评论0 收藏0
  • 详解javascript的类

    摘要:原文地址详解的类博主博客地址的个人博客从当初的一个弹窗语言,一步步发展成为现在前后端通吃的庞然大物。那么,的类又该怎么定义呢在面向对象编程中,类是对象的模板,定义了同一组对象又称实例共有的属性和方法。这个等同于的属性现已弃用。。 前言 生活有度,人生添寿。 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客   Javascript从当初的一个弹窗语言,一...

    marek 评论0 收藏0

发表评论

0条评论

jayzou

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<