JS模块化

184 阅读3分钟

一、模块化的理解

1、什么是模块?

  将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
  块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信

2、一个模块的组成

  数据--->内部的属性
  操作数据的行为--->内部的函数

3、模块化

  编码时是按照模块一个一个编码的, 整个项目就是一个模块化的项目

4、模块化的进化过程

全局function模式 :

编码: 全局变量/函数
问题: 污染全局命名空间, 容易引起命名冲突/数据不安全

namespace模式 :

编码: 将数据/行为封装到对象中
解决: 命名冲突(减少了全局变量)
问题: 数据不安全(外部可以直接修改模块内部的数据)

IIFE模式/增强

IIFE : 立即调用函数表达式--->匿名函数自调用
编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口
引入依赖: 通过函数形参来引入依赖模块
  ```
  (function(window, module2){
    var data = 'atguigu.com'
    function foo() {
       module2.xxx()
       console.log('foo()'+data)
    }
    function bar() {   
       console.log('bar()'+data)
    }

    window.module = {foo}
  })(window, module2)
  ```

5、案例

## 模块化进化史教程
1. 全局function模式
  * module1.js
    ```
    //数据
    let data = 'atguigu.com'

    //操作数据的函数
    function foo() {
      console.log(`foo() ${data}`)
    }
    function bar() {
      console.log(`bar() ${data}`)
    }
    ```
  * module2.js
    ```
    let data2 = 'other data'

    function foo() {  //与另一个模块中的函数冲突了
      console.log(`foo() ${data2}`)
    }
    ```
  * test1.html
    ```
    <script type="text/javascript" src="module1.js"></script>
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript">

      let data = "修改后的数据"
      foo()
      bar()
    </script>
    ```
   * 说明:
      * 全局函数模式: 将不同的功能封装成不同的全局函数
      * 问题: Global被污染了, 很容易引起命名冲突
2. namespace模式
  * module1.js
    ```
    let myModule = {
      data: 'atguigu.com',
      foo() {
        console.log(`foo() ${this.data}`)
      },
      bar() {
        console.log(`bar() ${this.data}`)
      }
    }
    ```
  * module2.js
    ```
    let myModule2 = {
      data: 'atguigu.com2222',
      foo() {
        console.log(`foo() ${this.data}`)
      },
      bar() {
        console.log(`bar() ${this.data}`)
      }
    }
    ```
  * test2.html
    ```
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript" src="module22.js"></script>
    <script type="text/javascript">
      myModule.foo()
      myModule.bar()

      myModule2.foo()
      myModule2.bar()

      myModule.data = 'other data' //能直接修改模块内部的数据
      myModule.foo()

    </script>
    ```
  * 说明
    * namespace模式: 简单对象封装
    * 作用: 减少了全局变量
    * 问题: 不安全
3. IIFE模式
  * module3.js
    ```
    (function (window) {
      //数据
      let data = 'atguigu.com'

      //操作数据的函数
      function foo() { //用于暴露有函数
        console.log(`foo() ${data}`)
      }

      function bar() {//用于暴露有函数
        console.log(`bar() ${data}`)
        otherFun() //内部调用
      }

      function otherFun() { //内部私有的函数
        console.log('otherFun()')
      }

      //暴露行为
      window.myModule = {foo, bar}
    })(window)
    ```
  * test3.html
    ```
    <script type="text/javascript" src="module3.js"></script>
    <script type="text/javascript">
      myModule.foo()
      myModule.bar()
      //myModule.otherFun()  //myModule.otherFun is not a function
      console.log(myModule.data) //undefined 不能访问模块内部数据
      myModule.data = 'xxxx' //不是修改的模块内部的data
      myModule.foo() //没有改变

    </script>
    ```
  * 说明:
    * IIFE模式: 匿名函数自调用(闭包)
    * IIFE : immediately-invoked function expression(立即调用函数表达式)
    * 作用: 数据是私有的, 外部只能通过暴露的方法操作
    * 问题: 如果当前这个模块依赖另一个模块怎么办?
4. IIFE模式增强
  * 引入jquery到项目中
  * module4.js
    ```
    (function (window, $) {
      //数据
      let data = 'atguigu.com'

      //操作数据的函数
      function foo() { //用于暴露有函数
        console.log(`foo() ${data}`)
        $('body').css('background', 'red')
      }

      function bar() {//用于暴露有函数
        console.log(`bar() ${data}`)
        otherFun() //内部调用
      }

      function otherFun() { //内部私有的函数
        console.log('otherFun()')
      }

      //暴露行为
      window.myModule = {foo, bar}
    })(window, jQuery)
    ``` 
  * test4.html
    ```
    <script type="text/javascript" src="jquery-1.10.1.js"></script>
    <script type="text/javascript" src="module4.js"></script>
    <script type="text/javascript">
      myModule.foo()
    </script>
    ```
  * 说明
    * IIFE模式增强 : 引入依赖
    * 这就是现代模块实现的基石

5. 页面加载多个js的问题
  * 页面:
    ```
    <script type="text/javascript" src="module1.js"></script>
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript" src="module3.js"></script>
    <script type="text/javascript" src="module4.js"></script>
    ```
  * 说明
    * 一个页面需要引入多个js文件
    * 问题:
        * 请求过多
        * 依赖模糊
        * 难以维护
    * 这些问题可以通过现代模块化编码和项目构建来解决

二、 模块化的好处、为什么要模块化

避免命名冲突(减少命名空间污染)
更好的分离, 按需加载(点对点,功能明确)
更高复用性
高可维护性

三、提出模块化之后,带来的问题是什么

请求过多
依赖模糊
难以维护

于是有了规范

四、模块化规范

1、CommonJS

1.1 规范说明

http://wiki.commonjs.org/wiki/Modules/1.1
每个文件都可当作一个模块
在服务器端: 在服务器端想要使用这个规范,那么要求,模块的加载是运行时同步加载的
在浏览器端: 浏览器等服务器返回需要很长时间,屏幕没页面展示,过长甚至404,于是,在浏览器端想要使用这个规范,那么要求,模块需要提前编译打包处理,比如因为浏览器不认识require,浏览器需要提前编译打包处理直到浏览器可以认识

1.2 基本语法

1.2.1 暴露模块

留意两者区别
module.exports = value 覆盖式的暴露
exports.xxx = value 可暴露多个模块
问题: 暴露的模块到底是什么?是exports这个对象

1.2.2 引入模块

require(xxx)
    1)第三方模块:xxx为模块名
    2)自定义模块: xxx为模块文件路径

1.3 配置

package.json
        {
          "name": "browserify-test",
          "version": "1.0.0",
          "main": "app.js",
          "description": "",
          "scripts": {
              "test": ""
          },
          "devDependencies":{ //开发时依赖
              "Browserify": "^14.1.1"
          },
          "dependencies": {  //运行时依赖
              "unique": "^1.0.1"
          }
    }

1.4 实现

1.4.1 服务器端实现

Node.js nodejs.cn/
Node.js 是一个服务器程序,服务器端 JavaScript,是一个基于 Chrome V8 引擎的 JavaScirpt 运行环境。最大优点是处理并行访问,处理高并发;采用事件驱动,异步编程,Javascript的匿名函数和闭包特性非常适合事件驱动、异步编程;Nodejs语法完全是js语法;
Node.js模块化教程
1. 下载安装node.js
2. 创建项目结构
  ```
  |-modules
    |-module1.js
    |-module2.js
    |-module3.js
  |-app.js
  |-package.json
//这是package.json的内容,其实通过npm init并给与名字等配置信息就可以自动生成此文件
    {
      "name": "commonJS-node",//写明包名
      "version": "1.0.0"//该包的版本号
      "main": "app.js"
      "description": ""
      "scripts": {
          "test": ""
      }
    }
  ```
3. 下载第三方模块
  * npm install uniq --save
4. 模块化编码
  * module1.js
    ```
    module.exports = {
      foo() {
        console.log('moudle1 foo()')
      }
    }
    ```
  * module2.js
    ```
    module.exports = function () {
      console.log('module2()')
    }
    ```
  * module3.js
    ```
    exports.foo = function () {
      console.log('module3 foo()')
    }

    exports.bar = function () {
      console.log('module3 bar()')
    }
    
    exports.arr = [3, 3, 5, 6, 8]
    ```
  * app.js 
    ```
    /**
      1. 定义暴露模块:
        module.exports = value;
        exports.xxx = value;
      2. 引入模块:
        var module = require(模块名或模块路径);
     */
    "use strict";
    //引用模块  第三方库最好放在自定义库的上面
    let uniq = require('uniq')
    let fs = require('fs')
    
    let module1 = require('./modules/module1')
    let module2 = require('./modules/module2')
    let module3 = require('./modules/module3')

    //使用模块  体会暴露的本质
    module1.foo()
    module2()
    module3.foo()
    module3.bar()

    console.log(uniq([1, 3, 1, 4, 3]))//[1,3,4]uniq去重
    let result = uniq(module3.arr)
    console.log(result)

    fs.readFile('app.js', function (error, data) {
      console.log(data.toString())
    })
    ```
5. 通过node运行app.js 这样就可以看到打印内容了
  * 命令: node app.js
  * 工具: 右键-->运行

1.4.2 浏览器端实现

Browserify browserify.org/
Browserify是一个Javascript的库,也称为CommonJS的浏览器端的打包工具,可以用来把多个Module打包到一个文件中,并且能很好地应对Modules之间的依赖关系。而Module是封装了属性和功能的单元,是一个Javascript对象,Modules之间可以相互依赖。某种程度上来说,Browserify模仿了Node.js加载Module的方式。一个js文件包含一个Module。所以,Browserify通过读取文件来加载该文件内的Module。
Browserify模块化使用教程
1. 创建项目结构
  ```
  |-js
    |-dist //打包生成文件的目录
    |-src //源码所在的目录
      |-module1.js
      |-module2.js
      |-module3.js
      |-app.js //应用主源文件
  |-index.html
  |-package.json
    {
      "name": "browserify-test",
      "version": "1.0.0",
      "devDependencies":{ //开发时依赖
          "Browserify": "^14.1.1"
      }
      "dependencies": {  //运行时依赖
          "unique": "^1.0.1"
      }
      
    }
  ```
2. 下载browserify  它要求两个都要装  -dev模式表示对应的该模块只在开发的时候用的上
  * 全局: npm install browserify -g //生产环境、上线的时候用
  * 局部: npm install browserify --save-dev//开发的时候用
3. 定义模块代码
  * module1.js
    ```
    module.exports = {
      foo() {
        console.log('moudle1 foo()')
      }
    }
    ```
  * module2.js
    ```
    module.exports = function () {
      console.log('module2()')
    }
    ```
  * module3.js
    ```
    exports.foo = function () {
      console.log('module3 foo()')
    }

    exports.bar = function () {
      console.log('module3 bar()')
    }
    ```
  * app.js (应用的主js)
    ```
    //引用模块
    let module1 = require('./module1')
    let module2 = require('./module2')
    let module3 = require('./module3')

    let uniq = require('uniq')

    //使用模块
    module1.foo()
    module2()
    module3.foo()
    module3.bar()

    console.log(uniq([1, 3, 1, 4, 3]))
    ```
* 打包处理js:
   因为浏览器不认识require,你直接在index.html页面引入该app.js文件,会报错,必须要先经过browserify的编译打包处理。下面的-o表示output,把左边路径文件内容的打包到右边路径文件里
  * browserify js/src/app.js -o js/dist/bundle.js
* index.html页面使用引入,记住引入的是打包好的那个bundle.js文件才行:
  ```
  <script type="text/javascript" src="js/dist/bundle.js"></script> 
  ```
然后就能在控制台输出看到你的打印了
这里一定要留意到,browserify与nodejs操作使用过程的区别以及原因

1.4.3 区别Node与Browserify

Node.js 在服务器端使用这个规范,需要运行时动态同步加载模块
Browserify 在浏览器端使用这个规范,需要在转译(编译)时就会加载打包(合并)require的模块,说白了,就是在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了),运行的是打包生成的js, 运行时不存在需要再从远程引入依赖模块

实际上,出现顺序是common.js服务器端--AMD--common.js浏览器端

2、AMD : 浏览器端

2.1 规范说明

Asynchronous Module Definition(异步模块定义)
https://github.com/amdjs/amdjs-api/wiki/AMD
专门用于浏览器端, 模块的加载是异步的 

2.2 基本语法

2.2.1 定义暴露模块

//define定义没有依赖的模块,return暴露模块
define(function(){
        return 模块
})
//define定义有依赖的模块,return暴露模块,又称“显示声明,依赖注入”,
//依赖模块名与参数一一对应
define(['依赖模块名module1', '依赖模块名module2'], function(m1, m2){
        return 模块
})

2.2.2 引入使用模块

require(['module1', 'module2'], function(m1, m2){
    使用模块对象m1/m2
})

2.3 配置

require.config({
          //基本路径
          baseUrl : 'js/',
          //标识名称与路径的映射
          paths : {
            '模块1' : 'modules/模块1',
            '模块2' : 'modules/模块2',
            'angular' : 'libs/angular',
            'angular-messages' : 'libs/angular-messages'
          },
          //非AMD的模块
          shim : {
            'angular' : {
                exports : 'angular'
            },
            'angular-messages' : {
                exports : 'angular-messages',
                deps : ['angular']
            }
          }
        })

2.4 实现(浏览器端)

2.4.1 NoAMD,没有使用AMD规范的写法

//dataService.js文件  定义一个没有依赖的模块
(function(window) {
    let name = "dataService.js";
    function getName() {
        return name
    };
    window.dataService = {getName}//说白了,直接放到window上
})(window) 

//alert.js文件   定义一个有依赖的模块
   (function(window, dataService) {
    let msg = "alert.js";
    function showMsg() {
        console.log(msg, dataService.getName())
    };
    window.alerter = {showMsg}
})(window, dataService) 

 //app.js文件   定义主模块,汇集所有模块,引入模块
 (function(alerter) {
    alerter.showMsg();
})(alerter) 

//页面使用,即要在html页面中引入,注意顺便不能乱
<script type="text/javascript" src="./js/dataService.js"></script> 
<script type="text/javascript" src="./js/alerter.js"></script> 
<script type="text/javascript" src="./app.js"></script> 
 此时,才能看到打印信息
 该暴露暴露,该引入引入,都得指示明白,这就是模块化   
 

2.4.2 使用AMD规范的写法,以require.js为例

require.js 是 AMD 的一个实现。require.js 是一个 JavaScript 模块加载器。它非常适合在浏览器中使用,但它也可以用在其他脚本环境,就像 Rhino and Node。使用RequireJS加载模块化脚本将提高代码的加载速度和质量。
require.js使用教程
1. 下载require.js, 并引入
  * 官网: http://www.requirejs.cn/
  * github : https://github.com/requirejs/requirejs
  * 将require.js导入项目: js/libs/require.js 
2. 创建项目结构
  ```
  |-js
    |-libs
      |-require.js
    |-modules
      |-alerter.js
      |-dataService.js
    |-main.js
  |-index.html
  ```
3. 定义require.js的模块代码

  * dataService.js 定义没有依赖的模块
    ```
    define(function () {
      let msg = 'atguigu.com'
      function getMsg() {
        return msg.toUpperCase()
      }

      return {getMsg}
    })
    ```
    
  * alerter.js 定义有依赖的模块
    ```
    define(['dataService', 'jquery'], function (dataService, $) {
      let name = 'Tom2'

      function showMsg() {
        $('body').css('background', 'gray')
        alert(dataService.getMsg() + ', ' + name)
      }

      return {showMsg}
    })
    ```
    
4. 主模块(应用入口): main.js
  ```
  (function () {
      //配置
      require.config({
        //基本路径
        baseUrl: 'js/',//出发点不同,站在根目录下看路径
        //映射: 模块标识名: 路径
        paths: {//出发点不同,站在main.js角度看路径
          //自定义模块
          'alerter': 'modules/alerter',//不需要加.js
          'dataService': 'modules/dataService',

          //库模块
          'jquery': 'libs/jquery-1.10.1',
          'angular': 'libs/angular'

        },

        //配置不兼容AMD的模块
        shim: {
          angular: {
            exports: 'angular'
          }

        }
      })

      //引入模块使用,通过requirejs()
      requirejs(['alerter', 'angular'], function (alerter, angular) {
        alerter.showMsg()
        console.log(angular);
      })
    })()
      ```

    5. 页面使用模块:
       在index.html文件里使用,【src="js/libs/require.js"】是引入规范的库,
       【data-main="js/main.js"】表明主模块
      <script type="text/javascript" src="js/libs/require.js" data-main="js/main.js"></script>

以上注意到,要在两个地方引入:

    main.js文件的paths和requirejs()引入;
    html文件的<script>引入

       (第三方库jquery支持AMD,都能支持require.js的模块加载)
    6. 使用第三方基于require.js的框架(jquery)
      * 将jquery的库文件导入到项目: 
        * js/libs/jquery-1.10.1.js
      * 在main.js中配置jquery路径
        ```
        paths: {
                  'jquery': 'libs/jquery-1.10.1'//注意jquery小写
              }
        ```
      * 在alerter.js中使用jquery
        ```
        define(['dataService', 'jquery'], function (dataService, $) {
            var name = 'xfzhang'
            function showMsg() {
                $('body').css({background : 'red'})
                alert(name + ' '+dataService.getMsg())
            }
            return {showMsg}
    })
    ```

  (并不是所有第三方库都支持AMD,都能支持require.js的模块加载,需要单独配置shim)
7. 使用第三方不基于require.js的框架(angular/angular-messages)
  * 将angular.js和angular-messages.js导入项目
    * js/libs/angular.js
    * js/libs/angular-messages.js
  * 在main.js中配置
    ```
    (function () {
      require.config({
        //基本路径
        baseUrl: "js/",
        //模块标识名与模块路径映射
        paths: {
          //第三方库
          'jquery' : 'libs/jquery-1.10.1',
          'angular' : 'libs/angular',
          'angular-messages' : 'libs/angular-messages',
          //自定义模块
          "alerter": "modules/alerter",
          "dataService": "modules/dataService"
        },
        /*
         配置不兼容AMD的模块
         exports : 指定导出的模块名
         deps  : 指定所有依赖的模块的数组
         */
        shim: {
          'angular' : {
            exports : 'angular'
          },
          'angular-messages' : {
            exports : 'angular-messages',
            deps : ['angular']
          }
        }
      })
      //引入使用模块
      require( ['alerter', 'angular', 'angular-messages'], function(alerter, angular) {
        alerter.showMsg()
        angular.module('myApp', ['ngMessages'])
        angular.bootstrap(document,["myApp"])
      })
    })()
    ```
  * 页面:
    ```
    <form name="myForm">
      用户名: <input type="text" name="username" ng-model="username" ng-required="true">
      <div style="color: red;" ng-show="myForm.username.$dirty&&myForm.username.$invalid">用户名是必须的</div>
    </form>
    ```
  
  
  
    

3、CMD : 浏览器端

老师说CMD规范了解即可

3.1 规范说明

 Common Module Definition(通用模块定义)
https://github.com/seajs/seajs/issues/242
专门用于浏览器端, 模块的加载是异步的 
模块使用时才会加载执行,懒执行

3.2 基本语法

3.2.1 定义暴露模块

//通过module/exports 、 exports.xxx = value来暴露模块

//定义没有依赖的模块
define(function(require, exports, module){
    exports.xxx = value
    module.exports = value
})

//定义有依赖的模块
define(function(require, exports, module){
    //引入依赖模块(同步)
    var module2 = require('./module2')
    //引入依赖模块(异步)
    require.async('./module3', function (m3) {
     })
     //暴露模块
    exports.xxx = value
})

3.2.2 引入使用模块

//通过require引入依赖模块
define(function (require) {
    var m1 = require('./module1')
    var m4 = require('./module4')
    m1.show()
    m4.show()
})

3.3 配置

* sea.js是CMD的实现
* 使用模块seajs.use(['模块1', '模块2'])

3.4 实现(浏览器端)

sea.js简单使用教程
1. 下载sea.js, 并引入
  * 官网: http://seajs.org/
  * github : https://github.com/seajs/seajs
  * 将sea.js导入项目: js/libs/sea.js 
2. 创建项目结构
  ```
  |-js
    |-libs
      |-sea.js
    |-modules
      |-module1.js
      |-module2.js
      |-module3.js
      |-module4.js
      |-main.js
  |-index.html
  ```
3. 定义sea.js的模块代码
  * module1.js
    ```
   define(function (require, exports, module) {
      //内部变量数据
      var data = 'atguigu.com'
      //内部函数
      function show() {
        console.log('module1 show() ' + data)
      }
      //向外暴露
      exports.show = show
    })
    ```
  * module2.js
    ```
    define(function (require, exports, module) {
      module.exports = {
        msg: 'I Will Back'
      }
    })
    ```
  * module3.js
    ```
    define(function (require, exports, module) {
      const API_KEY = 'abc123'
      exports.API_KEY = API_KEY
    })
    ```
  * module4.js
    ```
    define(function (require, exports, module) {
      //引入依赖模块(同步)
      var module2 = require('./module2')

      function show() {
        console.log('module4 show() ' + module2.msg)
      }

      exports.show = show
      //引入依赖模块(异步)
      require.async('./module3', function (m3) {
        console.log('异步引入依赖模块3  ' + m3.API_KEY)
      })
    })
    ```
  * main.js : 主(入口)模块
    ```
   define(function (require) {
      var m1 = require('./module1')
      var m4 = require('./module4')
      m1.show()
      m4.show()
    })
    ```
4. index.html:
  ```
  <!--
  使用seajs:
    1. 引入sea.js库
    2. 如何定义导出模块 :
      define()
      exports
      module.exports
    3. 如何依赖模块:
      require()
    4. 如何使用模块:
      seajs.use()
  -->
  //顺序不可乱
<script type="text/javascript" src="js/libs/sea.js"></script>
<script type="text/javascript">
  seajs.use('./js/modules/main')
</script>
  ```
最后打印: module1 module2 module4 module3

4、ES6

4.1 规范说明

* ES6是 JavaScript 语言的下一代标准 
* http://es6.ruanyifeng.com/#docs/module
* 和common.js一样,依赖模块需要编译打包处理,因为ES6自己是JavaScript原生语言支持实现的模块化,可是现代浏览器大多都还未支持,所以必须使用Babel将ES6编译为ES5代码,使用Browserify编译打包js
* 问题: 所有浏览器还不能直接识别ES6模块化的语法  
* 解决:
    使用Babel将ES6--->ES5(使用了CommonJS) ----浏览器还不能直接执行
    使用Browserify--->打包处理----浏览器可以运行

4.2 基本语法

4.2.1 导出模块 export

* 暴露一个对象: 
  export default 对象
  
* 暴露多个: 
  export var xxx = value1
  export let yyy = value2

  var xxx = value1
  let yyy = value2
  export {xxx, yyy}

4.2.2 引入模块 import

* default模块:
  import xxx  from '模块路径/模块名'
  
* 其它模块
  import {xxx, yyy} from '模块路径/模块名'
  import * as module1 from '模块路径/模块名'
  

4.3 配置

//package.json
{
    "name": "es6-babel-browserify",
    "version": "1.0.0",
    "devDependencies": {
        "babel-preset-es2015": "^6.24.0"
    }
}
//.babelrc文件
{
    "presets": ["es2015"]
}

4.4 实现(浏览器端)

ES6-Babel-Browserify使用教程
1. 定义package.json文件
  ```
  {
    "name" : "es6-babel-browserify",
    "version" : "1.0.0"
  }
  ```
2. 安装babel-cli, babel-preset-es2015和browserify
    * npm install babel-cli browserify -g
    * npm install babel-preset-es2015 --save-dev 
    备注:其中,cli为command line interface命令行接口
    
3. 定义.babelrc文件
```
{
    "presets": ["es2015"]
}
```
4. 编码
  * js/src/module1.js  分别暴露
    ```
    export function foo() {
      console.log('module1 foo()');
    }
    export let bar = function () {
      console.log('module1 bar()');
    }
    export const DATA_ARR = [1, 3, 5, 1]
    ```
  * js/src/module2.js  统一暴露
    ```
    let data = 'module2 data'

    function fun1() {
      console.log('module2 fun1() ' + data);
    }

    function fun2() {
      console.log('module2 fun2() ' + data);
    }

    export {fun1, fun2}
    ```
  * js/src/module3.js  默认暴露
    ```
    export default {
      name: 'Tom',
      setName: function (name) {
        this.name = name
      }
    }
    ```
  * js/src/app.js  引入其他模块
    ```
    import {foo, bar} from './module1'
    import {DATA_ARR} from './module1'
    import {fun1, fun2} from './module2'
    import person from './module3'

    import $ from 'jquery'

    $('body').css('background', 'red')

    foo()
    bar()
    console.log(DATA_ARR);
    fun1()
    fun2()

    person.setName('JACK')
    console.log(person.name);
    ```
5. 编译
   //每一次改动代码,都要跑一次这两个命令行,太麻烦了,此时就要去学习【自动化构建工具】
  * 使用Babel将ES6编译为ES5代码(但包含CommonJS语法) : babel js/src -d js/lib
  * 使用Browserify编译js : browserify js/lib/app.js -o js/lib/bundle.js
  备注:以-d  -o 为分割线,把左边转换到右边
6. 页面中引入测试
  ```
  //注意引入的是哪一个文件
  <script type="text/javascript" src="js/lib/bundle.js"></script>
  ```
7. 引入第三方模块(jQuery)
  1). 下载jQuery模块: 
    * npm install jquery@1 --save
  2). 在app.js中引入并使用
    ```
    import $ from 'jquery'
    $('body').css('background', 'red')
    ```

五、SeaJS与RequireJS最大的区别

  • RequireJS AMD依赖前置,SeaJS CMD依赖后置
  • SeaJS只会在真正需要使用(依赖)模块时才执行该模块,SeaJS是异步加载模块的没错, 但执行模块的顺序也是严格按照模块在代码中出现(require)的顺序, 这样也许更符合逻辑。
  • RequireJS会先尽早地执行(依赖)模块, 相当于所有的require都被提前了, 而且模块执行的顺序也不一定100%就是先mod1再mod2 。因此你看到执行顺序和你预想的完全不一样。
  • 注意:这里说的是执行(真正运行define中的代码)模块, 而非加载(load文件)模块。模块的加载都是并行的, 没有区别,区别在于执行模块的时机,或者说是解析。
  • RequireJS的做法是并行加载所有依赖的模块, 并完成解析后, 再开始执行其他代码, 因此执行结果只会”停顿”1次, 完成整个过程是会比SeaJS要快.
  • 而SeaJS一样是并行加载所有依赖的模块, 但不会立即执行模块, 等到真正需要(require)的时候才开始解析, 这里耗费了时间, 因为这个特例中的模块巨大, 因此造成”停顿”2次的现象, 这就是我所说的SeaJS中的”懒执行”.