js模块化

一、什么是模块/模块化?

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

二、模块化的进化史

1、全局模式

全局函数模式: 将不同的功能封装成不同的全局函数。

弊端:Global被污染了, 很容易引起命名冲突

最早我们用全局模式写代码:

module1.js:
function bar() {
    console.log("bar()");
}

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

    bar()//bar() other--
    foo()//foo

}
</script>
</body>

2.namespace模式

namespace模式: 简单对象封装
作用: 减少了全局变量
问题: 不安全(数据不是私有的, 外部可以直接修改)

module1.js

let obj={
    data:"我爱你中国",
    bar(){
        console.log(`obj()-${this.data}`)
    }
}

module2.js

let obj2={
    data:"我爱你中国!!!!!!obj2",
    bar(){
        console.log(`obj2()-${this.data}`)
    }
}
<script type='text/javascript' src='module1.js'></script>
<script type='text/javascript' src='module2.js'></script>
<script type='text/javascript'>
  window.onload=function () {

    obj.bar()//obj()-我爱你中国
    obj2.bar()//obj2()-我爱你中国!!!!!!obj2
    obj.data="libufan" //外部可以直接修改
    obj.bar()//obj()-libufan

  }
</script>

3.IIFE模式

IFE模式: 匿名函数自调用(闭包)
IIFE : immediately-invoked function expression(立即调用函数表达式)
作用: 数据是私有的, 外部只能通过暴露的方法操作

module3.js:

(function (window) {
  //数据
  let data = 'libufan'

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

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

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

  //暴露行为
  window.myModule = {foo, bar}
})(window)
<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>

4.IIFE模式增强

 IIFE模式增强 : 引入依赖

这就是现代模块实现的基石

(function (window,$) {
    let data="wahaha"
    function bar() {
        console.log(`bar ${data}`)
        $('body').css("background","red")
    }
    function foo() {
        console.log("yaoyao")
        privateMe()

    }
    function privateMe() {
        console.log("私有")

    }
    window.myModule={bar,foo}
})(window,jQuery)

引入的js有顺序 

<body>
<script type='text/javascript' src='jquery-1.10.1.js'></script>
<script type='text/javascript' src='module4.js'></script>
<script type='text/javascript'>

  myModule.bar()//bar wahaha  页面红色
  myModule.foo()//yaoyao  私有
</script>
</body>

 

如果一个页面需要引入多个js文件
那么会发生很多问题:
  1). 请求过多
  2). 依赖模糊
  3). 难以维护

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript" src="module4.js"></script>
<script type="text/javascript" src="module3.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/jquery-1.10.1.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/test4.js"></script>
<script type="text/javascript">
  module.foo()
</script>

首先我们要依赖多个模块,那样就会发送多个请求,导致请求过多
然后就是依赖关系模糊  我们不知道他们的具体依赖关系是什么  也就是说很容易因为依赖关系导致出错
以上的现象就导致了这样会很难维护。很可能出现牵一发而动全身的情况导致项目出现严重的问题

这些问题可以通过现代模块化编码和项目构建来解决

三、模块化规范

一.CommonJS

规范说明:

  1. 每个文件(js)都可当作一个模块,
  2. 在服务器端:模块的加载运行时是同步加载的;
  3.  在浏览器端: 模块需要提前编译打包处理, 因为浏览器不认识node,需要把node编译成浏览器认识的东西

规范基本语法:

1,暴露模块

  1.     module.exports = value
  2.     exports.xxx = value
  3.     问题: 暴露的模块到底是什么?  是exports对象,初始值是一个空对象 { }

2,引入模块

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

 

CommonJS实现:

1.服务器端实现--CommonJS_Node模块化 

步骤:

1. 下载安装node.js
2. 创建项目结构
  ```
  |-modules
    |-module1.js
    |-module2.js
    |-module3.js
  |-app.js
  |-package.json
    {
      "name": "commonJS-node",
      "version": "1.0.0"
    }
  ```
3. 下载第三方模块 /举例模块,可下载任意模块
  * npm install uniq --save

4. 模块化编码

module1:
 

/**
 * 使用module.exports = value向外暴露一个对象
 */
"use strict"
module.exports = {
   bar(){
       console.log("bar() module1")
   }
}

module2:

/**
 * 使用module.exports = value向外暴露一个函数。函数将exports初始值空对象覆盖
 */
"use strict"
module.exports=function foo() {
    console.log("暴露方法foo() module2")
}

module3:

/* 暴露exports对象,给该对象添加不同的属性*/
exports.bar=function () {
    console.log("module3 bar()")

}
exports.foo=function () {
    console.log("module3 foo()")

}

app.js:主文件
 

/**
 1. 定义暴露模块:
 module.exports = value;
 exports.xxx = value;
 2. 引入模块:
 let module = require(模块名或模块路径);
 */
"use strict"
//引用模块
//let uniq = require('uniq')

let module1=require('./module/module1')//module1是一个对象
let module2=require('./module/module2')//因为module2暴露的是一个函数,所以module2是一个函数
let module3=require('./module/module3')//module3是exports对象

//console.log(uniq([1, 3, 1, 4, 3]))
module1.bar()//bar() module1
module2()//暴露方法foo() module2
module3.bar()//module3 bar()
module3.foo()//module3 foo()

2.浏览器端实现 --CommonJS-Browserify模块化

Browserify模块化使用步骤 :
1. 创建项目结构
  ```
  |-js
    |-dist //打包生成文件的目录
    |-src //源码所在的目录
      |-module1.js
      |-module2.js
      |-module3.js
      |-app.js //应用主源文件
  |-index.html
  |-package.json
    {
      "name": "browserify-test",
      "version": "1.0.0"
    }
  ```
2. 下载browserify--CommonJS的浏览器端的打包工具
  * 全局: npm install browserify -g
  * 局部: npm install browserify --save-dev  //dev参数表示只在项目开发时依赖
3. 定义模块代码

module1:

/**
 * 使用module.exports = value向外暴露一个对象
 */
module.exports = {
  foo() {
    console.log('moudle1 foo()')
  }
}

module2.js

/**
 * 使用module.exports = value向外暴露一个函数
 */
module.exports = function () {
  console.log('module2()')
}

module3.js

/**
 * 使用exports.xxx = value向外暴露一个对象
 */
exports.foo = function () {
  console.log('module3 foo()')
}

exports.bar = function () {
  console.log('module3 bar()')
}

app.js

/**
  1. 定义暴露模块:
    module.exports = value;
    exports.xxx = value;
  2. 引入模块:
    var module = require(模块名或模块路径);
*/
//引用模块

let uniq = require('uniq')

let module1 = require('./module1')
let module2 = require('./module2')
let module3 = require('./module3')


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

console.log(uniq([1, 3, 1, 4, 3]))

 

打包处理js:
  命令:
browserify js/src/app.js -o js/dist/bundle.js 
 // o 表示输出 ;o左边表示要打包的文件路径 右边表示打包后文件输出(存放)的路径

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--<script type="text/javascript" src="js/src/app.js"></script>-->
<!-- 引用打包后的文件-->
    <script type="text/javascript" src="js/dist/bundle.js"></script>
</body>
</html>

区别Node与Browserify
    Node.js运行时动态加载模块(同步)
    Browserify是在转译(编译)时就会加载打包(合并)require的模块

二、AMD模块化 

说明:

  1. Asynchronous Module Definition(异步模块定义)
  2. 专门用于浏览器端, 模块的加载是异步的 

基本语法:
    定义暴露模块:

   //定义没有依赖的模块
define(function(){
    return 模块
})

 //定义有依赖的模块
define(['module1', 'module2'], function(m1, m2){

//暴露模块的通信方法
    return 模块
})
    

引入使用模块:

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

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. 定义模块代码
dataService.js:

//定义没有依赖的模块
define(function () {

    let msg= ' nihao '
    
    function getMsg() {
        return msg.toUpperCase()
        
    }
    function myMessage() {
        console.log("mylibufan")
    }
//暴露模块的通信方法
  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. 应用主(入口)js: main.js
(function () {
//因为引入了require.js模块,所以可以用require方法
  //配置
  require.config({
    //基本路径
    baseUrl: 'js/',
    //映射: 模块标识名: 路径
    paths: {
      //自定义模块
      'alerter': 'modules/alerter',
      'dataService': 'modules/dataService',

      //库模块
      'jquery': 'libs/jquery-1.10.1',//jQuery支持require语法,内置jquery,所以 'jquery'小写
      'angular': 'libs/angular'
      
    },

    //配置不兼容AMD的模块
    //exports : 指定与相对应的模块名对应的模块对象
    shim: {
      angular: {
        exports: 'angular'
      }

    }
  })

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

})()

index.html:
 

<!DOCTYPE html>
<html>
<head>
  <title>Modular Demo 2</title>
</head>
<body>
<!--引入require.js并指定js主文件的入口-->
<script type="text/javascript" src="js/libs/require.js" data-main="js/main.js"></script>
</body>
</html>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值