首页 > 其他分享 >js 模块化

js 模块化

时间:2024-04-03 14:31:07浏览次数:19  
标签:function exports console log 模块化 js 模块

一、什么是模块化?

1.1 定义

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

 1.2 模块化的进化过程

 1.2.1 全局function模式
 * 全局函数模式: 将不同的功能封装成不同的全局函数
 * 问题: Global被污染了, 很容易引起命名冲突
 */

function foo() {
    console.log('foo()')
}
function bar() {
    console.log('bar()')
}

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

1.2.2 namespace模式 
/**
 * namespace模式: 简单对象封装
 * 作用: 减少了全局变量
 * 问题: 不安全(数据不是私有的, 外部可以直接修改)
 */
let myModule = {
  data: 'Jerry',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}
  •  减少了Global上的变量数目
  • 本质是对象,一点都不安全
 1.2.3 IIFE模式
/**
 * IIFE模式: 匿名函数自调用(闭包)
 * IIFE : immediately-invoked function expression(立即调用函数表达式)
 * 作用: 数据是私有的, 外部只能通过暴露的方法操作
 * 问题: 如果当前这个模块依赖另一个模块怎么办?
 */
(function (window) {
  //数据
  let data = 'Jerry'

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

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

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

  //暴露行为
  window.myModule = {foo, bar}
})(window)

  IIFE模式增强:引入依赖

(function (window, $) {
  //数据
  let data = 'Jerry'

  //操作数据的函数
  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)
  • IIFE : 立即调用函数表达式--->匿名函数自调用
  • 编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口
  • 引入依赖: 通过函数形参来引入依赖模块 

1.3 模块化的好处

  • 避免命名冲突(减少命名空间污染)
  • 更好的分离,按需加载
  • 更高复用性
  • 高可维护性
<body>
<!--
  1. 一个页面需要引入多个js文件
  2. 问题:
    1). 请求过多
    2). 依赖模糊
    3). 难以维护
  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>
</body>

 二、模块化规范

2.1  CommonJS

Node.js:     服务器端

Browserify :  浏览器端    也称为js的打包工具(CommonJs 浏览器端打包工具 )

// 基本语法:
      // 定义暴露模块 : exports
        exports.xxx = value
        module.exports = value

      // 引入模块 : require
        var module = require('模块名/模块相对路径')

 引入模块发生在什么时候?

  • Node : 运行时, 动态同步引入
  • Browserify : 在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了),  运行的是打包生成的js, 运行时不存在需要再从远程引入依赖模块
2.1.1 CommonJS-Node

代码示例:

module1.js   使用module.exports = value向外暴露一个对象

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

 module2.js     使用module.exports = value向外暴露一个对象

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

 module3.js      使用exports.xxx = value向外暴露多个对象

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

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

 使用时,用 require() 语法导入

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

let uniq = require('uniq')
let fs = require('fs')

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

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

fs.readFile('app.js', function (error, data) {
  console.log(data.toString())
})
2.1.2 CommonJS-Browserify 

 下载 browserify

  * 全局: npm install browserify -g

  * 局部: npm install browserify --save-dev

打包处理js:

browserify js/src/app.js -o js/dist/bundle.js

页面使用引入:

  <script type="text/javascript" src="js/dist/bundle.js"></script>

2.2 AMD - RequireJS

说明: 专门用于浏览器端,模块的加载是异步的     AMD · amdjs/amdjs-api Wiki · GitHub 

基本语法:

定义暴露模块:

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

// 定义有依赖的模块
define(['dataService', 'jquery'], function (dataService, $) {
  let name = 'Tom2'
    
  function showMsg() {
    $('body').css('background', 'gray')
    alert(dataService.getMsg() + ', ' + name)
  }
    
  return {showMsg}
})

引入使用模块:

//引入使用模块
requirejs( ['alerter'], function(alerter) {
  alerter.showMsg()
})

举例说明:alerter.js 依赖 dataService.js 和 jquery模块,可以在alerter.js中这样写:

/*
 定义有依赖的模块
 */
define(['dataService', 'jquery'], function (dataService, $) {
  let name = 'Tom2'

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

  return {showMsg}
})

 在 main.js 中引入依赖

(function () {
  //配置
  require.config({
    //基本路径
    baseUrl: 'js/',
    //映射: 模块标识名: 路径
    paths: {
      //自定义模块
      'alerter': 'modules/alerter',
      'dataService': 'modules/dataService',

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

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

    }
  })

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

在html页面中引入即可:

<!DOCTYPE html>
<html>
<head>
    <title>Modular Demo 2</title>
</head>
<body>
    <script type="text/javascript" src="js/libs/require.js" data-main="js/main.js"></script>
 </body>
</html>

关于 require.js 的详细用法可以参考:

Javascript模块化编程(三):require.js的用法 - 阮一峰的网络日志

2.3 CMD - SeaJS 

首先需要引入 sea.js的库

<script type="text/javascript" src="js/libs/sea.js"></script>
定义导出模块  define()  exports  module.exports

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
})
引入依赖模块   require()

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()
})
 使用模块  seajs.use()
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <!--
使用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>
  </body>
</html>

 2.4 ES6 模块化

依赖模块需要编译打包处理,使用Babel将ES6编译为ES5代码

export:导出模块,引入模块:import

1. 定义package.json 

2. 安装依赖包

安装babel-cli, babel-preset-es2015和browserify

 npm install babel-cli browserify -g 
 npm install babel-preset-es2015 --save-dev 
 presets 预设(将es6转换成es5的所有插件打包)

3. 定义.babelrc文件

{
   "presets": ["es2015"]
}

4. 编码

 module1.js 分别暴露

define(function (require, exports, module) {
  //内部变量数据
  var data = 'atguigu.com'
  //内部函数
  function show() {
    console.log('module1 show() ' + data)
  }

  //向外暴露
  exports.show = show
})

 module2.js  统一暴露

let data = 'module2 data'

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

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

export {fun1, fun2}

module3.js  export default

export default {
  name: 'Tom',
  setName: function (name) {
    this.name = name
  }
}

app.js 引入模块 import

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

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')

    

标签:function,exports,console,log,模块化,js,模块
From: https://blog.csdn.net/weixin_42289279/article/details/136028783

相关文章

  • 在静态页中,js和css使用虚拟路径指向网站根目录
    第一步:修改web.config<configuration><system.webServer><handlers><addname="x"verb="GET"path="*.css.ashx"type="FileResolver"/><addname="xx"verb=&quo......
  • 基于Node.js和ws库搭建WebSocket服务并实现消息互通的简单示例
    环境要求:Node.js环境安装npm(Node.js的包管理器)步骤:安装Node.js:如果你还没有安装Node.js,请从Node.js官网下载并安装。创建项目:创建一个新的目录作为项目文件夹,并在该目录下初始化一个新的Node.js项目。        mkdirmy-websocket-server        cdmy......
  • js 可以间接地“声明”或初始化变量的其他方式(除了直接使用var、let和const)
    在JavaScript中,除了直接使用var、let和const关键字来声明变量外,还有一些其他方式可以间接地“声明”或初始化变量。以下是一些示例:函数参数:当定义一个函数时,函数的参数列表中的每个参数实际上都会成为该函数作用域内的变量。这些变量在函数被调用时会被自动声明和初始化。func......
  • GIS入门,EPSG:3857介绍,纯JS如何实现简化得Web墨卡托投影的逆变换和高精度Web墨卡托投影
    EPSG:3857坐标系介绍EPSG:3857坐标系,也称为Web墨卡托投影(WebMercatorprojection),是一种用于Web地图的常见投影系统。它是由谷歌地图在2005年引入并广泛采用的。这个投影系统将地球表面的经纬度坐标转换为平面坐标,使得地图在Web上的显示更加方便和流畅。EPSG:3857坐标系使......
  • ASP.NET Core 使用 pdfjs 加载 实时水印 base64 编码的 PDF
    先下载pdfjs:https://github.com/mozilla/pdf.js目前最新版本是4.0.379把需要的文件放到项目下面,由于最新的pdfjs使用的mjs,看情况可以加下MIME类型:varprovider=newFileExtensionContentTypeProvider();provider.Mappings[".mjs"]="application/javascript";provider......
  • 界面控件DevExtreme JS & ASP.NET Core 2024年度产品规划预览(一)
    在本文中我们将介绍今年即将发布的v24.1附带的主要特性,这些特性既适用于DevExtreme JavaScript(Angular、React、Vue、jQuery),也适用于基于DevExtreme的ASP.NETMVC/Core控件。注意:本文中列出的功能和特性说明官方当前/预计的发展计划,此信息仅供参考之用,其中列出的功能/产品可......
  • TS全栈开发(React+Next.js+Nest.js+UniApp/Vue)项目
    IT环境  我们不可否认从事于互联网相关从业者从产品、开发、测试、运维、销售都吃信息化数字化的红利,对比其他行业薪资高。但从2020年大厂开始裁员、培训机构每年输送大量开发人员、整个国家政府企业工厂信息化建设完成差不多,你们会发现996加班,35岁被降薪裁员,相关IT从业人......
  • 分享three.js实现乐高小汽车
    前言Web脚本语言JavaScript入门容易,但是想要熟练掌握却需要几年的学习与实践,还要在弱类型开发语言中习惯于使用模块来构建你的代码,就像小时候玩的乐高积木一样。应用程序的模块化理念,通过将实现隐藏在一个简单的接口后面,您可以使您的应用程序万无一失且易于使用。它只做它应......
  • js实现websocket断线重连功能
    在项目开发中我们可能经常要使用websocket技术,当连接发生断线后,如果不进行页面刷新将不能正常接收来自服务端的推送消息。为了有效避免这种问题,我们需要在客户端做断线重连处理。当网络或服务出现问题后,客户端会不断检测网络状态,如果服务恢复,客户端则会自动重新连接,并断开......
  • Web前端(JS)
    1.JavaScript简介及其导入方式什么是JavaScript?JavaScript简称JS。JavaScript是一种轻量级、解释型、面向对象的脚本语言。它主要被设计用于在网页上实现动态效果,增加用户与网页的交互性。作为一种客户端脚本语言,JavaScript可以直接嵌入HTML,并在浏览器中执行。与HTML和CSS......