JavaScript模块化编程探究

跟着网站逐步变成”互联网运用顺序”,嵌入网页的Javascript代码愈来愈巨大,愈来愈庞杂。网页愈来愈像桌面顺序,须要一个团队分工合作、进度治理、单元测试等等……开辟者不能不运用软件工程的要领,治理网页的营业逻辑。
Javascript模块化编程,已成为一个急切的需求。

从CommonJS提及

CommonJS团队定义了module花样来处理JavaScript作用域题目,如许确保了每一个module都在本身的定名空间下实行。

依据CommonJS的范例,每一个文件就是一个模块,有本身的作用域。在一个文件内里定义的变量、函数、类,都是私有的,对其他文件不可见。

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

CommonJS给出2个东西来完成模块之间的依靠:

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

  2. 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,(想要在浏览器里翻开看看是什么模样)内容以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="world.js"></script>
</head>
<body>
    
</body>
</html>

效果在浏览器中翻开,检察控制台大失所望,报了一个毛病
world.js:2 Uncaught ReferenceError: require is not defined
发明浏览器不兼容CommonJS的根本原因,在于缺乏四个Node.js环境的变量:

  • module

  • exports

  • require

  • global
    只需能够供应这四个变量,浏览器就能够加载 CommonJS 模块,题目是能够处理的,然则彷佛并不怎样好玩,有兴致的朋侪能够去阮先生博客里走走啊传送门

如今我决议要去Node.js里边玩一下了

Node.js环境里玩一把

翻开命令行东西cd到项目目次:
《JavaScript模块化编程探究》

效果顺遂打印出了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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="a.js"></script>
</head>
<body>
    <span>body</span>
</body>
</html>

在浏览器中运转demo1.html,alert实行的时刻,html内容是一片空白的,即<span>body</span>并未被显现,当点击肯定后,才涌现,这就是JS壅塞浏览器衬着致使的效果。

RequireJS异步加载js模块

把a.js改写以下:

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

    test();
})

到githug下载require.jsRequireJS download修正demo1.html以下:

!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="require.js"></script>
    <script type="text/javascript">
        require(["a"]);
    </script>
</head>
<body>
    <span>body</span>
</body>
</html>

浏览器提醒了”it works”,申明运转准确,然则有一点不一样,此次浏览器并非一片空白,body已出如今页面中,目前为止能够晓得requirejs具有以下长处:

  1. 防备js加载壅塞页面衬着

  2. 治理模块之间的依靠性,便于代码的编写和保护,使得代码越发文雅。

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://segmentfault.com/a/1190000009336055
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞