首页 > 其他分享 >模块化基础知识

模块化基础知识

时间:2023-10-10 09:57:49浏览次数:42  
标签:function exports 基础知识 模块化 暴露 js 模块 foo

1 简介

1.1 模块

将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起

块的内部数据/实现是私有的, 只是向外暴露一些接口(方法)与外部其它模块通信

一个模块的组成:

  • 私有的数据:内部的变量
  • 私有的行为(操作数据):内部的函数
  • 向外暴露n个行为

1.2 模块化

描述一种特别的编码项目JS的方式:以模块为单元一个一个编写的

模块化的项目: JS编码时是按照模块一个一个编码的

模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块,可以提高了代码的复用性

、提高了代码的可维护性、可以实现按需加载

2 模块化的进化过程

2.1 全局function模式

编码: 全局变量/函数

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

案例:module1.js

// 数据
let data = 'module1.js'

// 操作数据的函数
function foo() {
  console.log(`foo() ${data}`)
}
function bar() {
  console.log(`bar() ${data}`)
}

module2.js

let data2 = 'module2.js';

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>

2.2 namespace模式: 简单对象封装

编码: 将数据/行为封装到对象中

解决: 命名冲突(减少了全局变量)

问题: 数据不安全(外部可以直接修改模块内部的数据)

案例:module1.js

let myModule = {
  data: 'module1.js',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}

module2.js

let myModule2 = {
  data: 'module2.js',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}

test2.html

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
  myModule.foo()
  myModule.bar()

  myModule2.foo()
  myModule2.bar()

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

2.3 IIFE模式/ IIFE 增强模式

IIFE : 立即调用函数表达式--->匿名函数自调用

编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口

引入依赖: 通过函数形参来引入依赖模块

(function(window, module2){
    var data = 'atguigu'
    function foo() {
       module2.xxx()
       console.log('foo()'+data)
    }
    function bar() {
       console.log('bar()'+data)
    }

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

3 CommonJS

Commonjs可以在服务器端(通过Nodejs)和浏览器端(通过Browserify)实现

nodejs是在运行时,动态同步引入到模块中的,而Browserify则是在运行前就对模块进行编译打包的处理(已经将依赖的模块包含进来了),运行的是打包生成的js, 运行时不存在需要再从远程引入依赖模块

3.1 基本语法

3.1.1 向外暴露成员:exports或module.exports

// 1.  分别向外暴露多个成员
exports.xxx = xxx
exports.yyy = yyy


// 2.  统一向外暴露多个成员
module.exports = {
    xxx,
    yyy
}

// 3.  默认只向外暴露一个成员
module.exports=XXX

只向外暴露一个成员,必须使用 module.exports=XXX 这种方式

3.1.2 引用使用模块 require

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

3.2 commonjs 模块原理

在 Node 中,每个模块内部默认都有一个自己的 module 对象

console.log(module)

// 返回结果:
  id: '.',
  exports: {},  // 默认也是一个对象
  parent: null,
  filename: 'E:\\nodejs\\资料\\03\\code\\1.js',
  loaded: false,
  children: [],
  paths:
   [ 'E:\\nodejs\\资料\\03\\code\\node_modules',
     'E:\\nodejs\\资料\\03\\node_modules',
     'E:\\nodejs\\资料\\node_modules',
     'E:\\nodejs\\node_modules',
     'E:\\node_modules' ] }

每个模块最后都会默认 return module.exports,所以如果你想要导出一个成员,直接给 exports 赋值是不起作用的

// 导出一个成员,直接给 exports 赋值是不管用的
exports='hello' 

// 必须是直接给 module.exports 直接赋值 才可以
module.exports='hello'

该 module 对象中,有一个成员叫:exports 也是一个对象,默认是空对象

console.log(module.exports)  // 返回结果:{}

也就是说如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports 中即可

因为每次导出接口成员的时候都通过 module.exports.xxx = xxx 的方式,Node 为了简化你的操作,专门提供了一个变量:exports 等于 module.exports

console.log(exports === module.exports) // true

exports.foo='bar'
// 等价于
module.exports.foo='bar'

案例:

// {foo: bar}
exports.foo = 'bar'

// {foo: bar, a: 123}
module.exports.a = 123

// exports !== module.exports
// 最终 return 的是 module.exports
// 所以无论你 exports 中的成员是什么都没用
exports = {
    a: 456
}

// {foo: 'haha', a: 123}
module.exports.foo = 'haha'

// 没关系,混淆你的
exports.c = 456

// 重新建立了和 module.exports 之间的引用关系了
exports = module.exports

// 由于在上面建立了引用关系,所以这里是生效的
// {foo: 'haha', a: 789}
exports.a = 789

// 前面再牛逼,在这里都全部推翻了,重新赋值
// 最终得到的是 Function
module.exports = function() {
    console.log('hello')
}

3.3 服务器端实现模块化

3.3.1 初始化项目

会自动生成一个 package.json配置文件

npm init -y

案例的目录结构如下:

|-modules
|-module1.js
|-module2.js
|-module3.js
|-app.js
|-package.json
{
  "name": "Commonjs-Nodejs",
  "version": "1.0.0"
}

3.3.2 安装项目依赖

# 用于数组去重
npm install uniq --save  
# 或者是下面的简写
npm i -S uniq 

3.3.3 模块化编码案例代码

module1.js

向外 暴露一个 对象:module.exports=XXX

 // 向外暴露一个 对象
 module.exports = {
   foo() {
     console.log('向外暴露一个对象:module1 foo()')
   }
 }

module2.js

向外 暴露一个 函数:module.exports=XXX

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

module3.js

// 分别向外暴露 成员
exports.foo = function () {
  console.log('分别向外暴露对象:module3 foo()')
}

exports.bar = function () {
  console.log('分别向外暴露对象:module3 bar()')
}

exports.arrData=[1,2,3,4,2,5,6,8,31,22]

// 或者一次性向外暴露多个成员
function foo(){
    console.log('分别向外暴露对象:module3 foo()')
}
function bar(){
    console.log('分别向外暴露对象:module3 bar()')
}
module.exports={
    foo:foo,
    bar:bar,
    arrData:arrData
}
// 还可以简写为:
module.exports={
    foo,
    bar,
    arrData
}

app.js:主模块文件

// 引入核心模块
const fs = require('fs')
// 引入第三方模块
const uniq = require('uniq')
// 引入自定义模块
const module1 = require('./modules/module1')
const module2 = require('./modules/module2')
const module3 = require('./modules/module3')

// 使用模块
module1.foo(); //module1是暴露的一个对象,对象是一个函数

module2(); //module2是暴露的一个函数

module3.foo() //module3是暴露的一个对象
module3.bar() //module3是暴露的一个对象
//使用第三方包(uniq数组去重)
console.log(uniq(module3.arrData))

3.3.4 通过node运行编译 app.js

node app.js

3.4 浏览器端实现模块化

3.4.1 初始化项目

会自动生成一个 package.json配置文件

npm init -y

案例的目录结构如下:

|-js
|-dist // 打包生成文件的目录
|-src // 源码所在的目录
  |-module1.js
  |-module2.js
  |-module3.js
  |-app.js / /应用主源文件
|-index.html
|-package.json
{
  "name": "browserify-test",
  "version": "1.0.0"
}

3.4.2 安装项目依赖

# 全局安装
npm install browserify -g

# 项目局部安装  --save-dev 开发依赖
npm install browserify --save-dev

3.4.3 定义模块代码

module1.js

 // 向外暴露一个对象
 module.exports = {
   foo() {
     console.log('向外暴露一个对象:module1 foo()')
   }
 }

module2.js

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

module3.js

 // 分别向外暴露成员 foo bar arrData
 exports.foo = function () {
   console.log('分别向外暴露对象:module3 foo()')
 }

 exports.bar = function () {
   console.log('分别向外暴露对象:module3 bar()')
 }

 exports.arrData=[1, 3, 1, 4, 3]

// 或者一次性向外暴露多个成员
module.exports={
    foo,
    bar,
    arrData
}

app.js (应用的主js):主模块js文件

   //引用模块
   const module1 = require('./module1')
   const module2 = require('./module2')
   const module3 = require('./module3')
   //使用模块
   module1.foo()

   module2()

   module3.foo()
   module3.bar()

3.4.4 打包编译处理js

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

4 ES6模块化

ES6本身就内置了模块化的实现,但是目前并不是所有浏览器都能直接识别ES6模块化的语法 ,一个好的解决方案是使用 webpack编译打包

4.1 基本语法

4.1.1 向外暴露成员:export

// 1. 默认暴露一个成员
export default 成员

// 2. 分别暴露多个成员
export const a = value1 // 分别暴露一个成员
export let b = value2 // 分别暴露一个成员

// 3. 统一暴露多个成员
const c = value1
let d = value2
export { c, d }

4.1.2 引用使用模块 import

// 1. 引入default默认暴露的模块:
import xxx from '模块路径/模块名'

// 2. 引入一般模块
import { a, b } from '模块路径/模块名'
import * as module1 from '模块路径/模块名'

4.2 模块化实现

4.2.1 向外暴露成员

module1.js :分别向外暴露多个成员 export XXX

export function foo() {
  console.log('module1 foo()')
}

export function bar() {
  console.log('module1 bar()')
}

export const DATA_ARR = [1, 3, 5, 1]

module2.js :统一向外暴露多个成员 export {XXX,YYY}

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 XXX

默认暴露:可以暴露任意数据类型,暴露什么数据,就可以接收什么数据

默认暴露只能向外暴露一次

// 1.  默认暴露一个函数
export default () => {
  console.log('我是默认暴露的箭头函数')
}

// 2.  默认暴露一个对象
export default {
    msg: 'hello world',
    foo() {
        console.log('我是默认暴露里面的回调函数:'+this.msg.toUpperCase())
    }
}

4.2.2 引入使用模块 import

1、 如果模块文件采用的是: 分别向外暴露多个成员统一向外暴露多个对象 的方式,那么引入模块的时候,可以采用 对象解构的方式

import {foo, bar, DATA_ARR} from './module1';
foo();
bar();
console.log(DATA_ARR);

import {fun1, fun2} from './module2';
fun1();
fun2();

2、 如果模块文件采用的是:默认暴露的方式,可以直接获取模块

import module3 from './module3'
module3();

3、 引入第三方模块

//引入第三方模块
import $ from 'jquery';
$('body').css('background', 'red')

4.3 浏览器端实现模块化

4.3.1 项目说明

1、 使用 Babel 将 ES6 编译为 ES5 代码

2、 使用 Browserify 编译打包 js

Browserify编译参考文档

4.3.2 实现步骤

1 初始化项目

npm init -y

2 安装项目依赖

# 安装babel依赖:
npm i @babel/core @babel/cli @babel/preset-env -D

# 安装browserify依赖:
npm install browserify -D

3 配置文件

新建 .babelrc 文件,配置babel预设(或者文件名为: babel.config.json

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
           "ie":"10", //这个是自己添加的,最好是加上
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "usage"  (这个选项可以不写)
      }
    ]
  ]
}

4 编码

module1.js:分别暴露多个成员

export function foo() {
  console.log('module1 foo()')
}

export function bar() {
  console.log('module1 bar()')
}

export const DATA_ARR = [1, 3, 5, 1]

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 () => {
  console.log('我是默认暴露的箭头函数')
}

module4.js:默认暴露一个对象

//默认暴露一个对象
 export default {
   msg: 'hello world',
   foo() {
     console.log('我是默认暴露里面的回调函数:'+this.msg.toUpperCase())
   }
 }

main.js:主模块文件

import {foo, bar, DATA_ARR} from './module1';
foo();
bar();
console.log(DATA_ARR);

import {fun1, fun2} from './module2';
fun1();
fun2();

//采用默认暴露的方式:引入模块的方法
import module3 from './module3'
module3();

import module4 from './module4'
module4.foo();

//引入第三方模块
import $ from 'jquery';
$('body').css('background', 'red')

5 编译

1、 使用Babel将ES6编译为ES5代码

babel js/src -d js/build

2、 使用Browserify编译js :

browserify js/build/main.js -o js/build/bundle.js

5 AMD require.js

基本语法

	// 定义要向外暴露的模块:    
	define([依赖模块名], function() {
	    return 模块
	})

	// 引入模块:       
	require(['模块1', '模块2'], function(m1, m2) {
	    //使用m1与m2
	})

	//配置     
	require.config({
	    // 基本路径        
	    baseUrl: 'src/',
	    //映射: 模块标识名: 路径       
	    paths: {
	        //自定义模块       
	        'a': 'modules/a', // 可以不加后缀名  
	        'b': 'modules/b', //第三方库
	        'jquery': 'libs/jquery-1.10.1',
	    }
	})

5.1 如何在浏览器端实现模块化

主要是通过 require.js 在浏览器端实现模块化

5.1.1 下载require.js 并引入

5.1.2 创建项目结构

|-js
|-libs
  |-require.js
|-modules
  |-alerter.js
  |-dataService.js
|-main.js
|-index.html

5.1.3 定义require.js的模块代码

dataService.js:没有依赖的模块

  //定义没有 依赖 的模块
  define(function () {
    const msg = 'dataService.js'

    // 将字符串转化为大写
    function getMsg() {
      return msg.toUpperCase()
    }

    // 返回大写的 HELLO WORLD
    // 向外暴露模块 return
    return { getMsg }
  })      

alert.js:定义有 依赖 的模块

  // 定义有依赖的模块:依赖项dataService jquery
  define(['dataService', 'jquery'], function (dataService, $) {
    const name = 'alert.js'
    function showMsg() {
      $('body').css('background', 'red')
      alert(dataService.getMsg() + ', ' + name)
    }

    return {showMsg}
  })

5.1.4 主程序文件: main.js

(function () {
//配置
requirejs.config({
  //基本路径(相对于根目录)
  baseUrl: "js/",
  //模块标识名与模块路径映射
  paths: {
    "dataService": "modules/dataService",
    "alert": "modules/alert",
    //引入 第三方模块 (前提是jquery是支持AMD的,如果第三方库不支持AMD,则不可以引入)
    "jquery": "libs/jquery-3.3.1.min",
  }
})

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

5.1.4 页面使用模块

配置data-main属性和src属性

<script data-main="js/main" src="js/libs/require.js"></script>

5.2 使用基于require.js的第三方框架(jQuery)

1、 将jquery的库文件导入到项目:

js/libs/jquery-1.10.1.js

2、 在main.js中配置jquery路径,设置映射

paths: {
          'jquery': 'libs/jquery-1.10.1'
      }

3、 在alerter.js中使用jquery

define(['dataService', 'jquery'], function (dataService, $) {
    var name = 'xfzhang'
    function showMsg() {
        $('body').css({background : 'red'})
        alert(name + ' '+dataService.getMsg())
    }
    return {showMsg}
})

5.3 使用第三方不基于require.js的框架(angular)

1、 将angular.js导入项目 js/libs/angular.js

2、 在main.js中配置

(function () {
  require.config({
    //基本路径
    baseUrl: "js/",
    //模块标识名与模块路径映射
    paths: {
      //第三方库
      'jquery' : './libs/jquery-1.10.1',
      'angular' : './libs/angular',
      //自定义模块
      "alerter": "./modules/alerter",
      "dataService": "./modules/dataService"
    },
    /*
     配置不兼容AMD的模块
     exports : 指定与相对应的模块名对应的模块对象
     */
    shim: {
      'angular' : {
        exports : 'angular'
      }
    }
  })
  //引入使用模块
  require( ['alerter', 'angular'], function(alerter, angular) {
    alerter.showMsg()
    console.log(angular);
  })
})()

6 CMD sea.js

基本语法:

// 定义暴露模块:
define(function(require, module, exports) {
    // 通过require()引入依赖模块        
    // 通过module/exports来暴露模块      
    exports.xxx = value
})

//  使用模块:	
seajs.use(['模块1', '模块2'])

6.1 如何在浏览器端实现模块化

CMD主要是通过 sea.js 在浏览器端实现模块化

6.1.1 下载Sea.js第三方包

seajs官方网站

6.1.2 创建项目结构

|-js
|-libs
  |-sea.js
|-modules
  |-module1.js
  |-module2.js
  |-module3.js
  |-module4.js
  |-main.js
|-index.html

6.1.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()
})
  1. 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>

标签:function,exports,基础知识,模块化,暴露,js,模块,foo
From: https://www.cnblogs.com/songxia/p/17753797.html

相关文章

  • js1之基础知识
    1简介1.1计算机语言计算机语言指用于人与计算机之间通讯的语言,它是人与计算机之间传递信息的媒介。总的来说,可以分成机器语言,汇编语言和高级语言三大类。实际上计算机最终所执行的都是机器语言,它是由“0”和“1”组成的二进制数,二进制是计算机语言的基础。0=000000001=00......
  • MongoDB基础知识
    1.简介MongoDB官方文档菜鸟教程1、NoSQL(NotOnlySQL),不仅仅是SQL,主要是指非关系型数据库,是对不同与传统的关系型数据库的数据管理系统的统称2、NoSQL用于超大规模数据的存储,这些类型的数据存储吧需要固定的模式,无需多余的操作就可以横向扩展1.2NoSQL和RDBMS的区分......
  • 01webpack基础知识
    1概述1.1什么是webpack1、webpack是一种前端资源构建工具,一个静态模块打包器(modulebundler)。在webpack看来,前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)2、webpack是一个前......
  • 计算机基础知识
    计算机基础知识计算机简介​ 计算机俗称电脑,是第二次世界战争时,美国国防部利用它来进行弹道计算。第一台通用计算机叫做:ENIAC。当时计算机是一个庞然大物,用了18000个电子管,占地170平方米,重达30吨,耗电功率约150千瓦,每秒钟可进行5000次运算。​ 随着时间和科技的不断进步,直到发展......
  • Kubeflow基础知识
    kubeflow基础知识kubeflow简介kubeflow是谷歌开源的MLOps开源平台,其中包含的不同组件代表了机器学习生命周期的不同阶段。下图是kubeflow组织ML工作流程:kubeflow组件介绍1.kubeflowPipelinespipelines是对机器学习工作流的一种描述,当运行一个pipeline时系统会启动一......
  • 【一】基础知识
    【小结】1.汇编指令是机器语言的助记符,同机器指令一一对应。2.每一种CPU都有自己的汇编指令集。3.CPU可以直接使用的信息在存储器中存放4.在存储器中指令和数据没有任何区别,都是二进制信息。5.存储单元从零开始顺序编号。6.一个存储单元可以存储8个bit,即8位二进制数。7.1B......
  • java基础知识总结,javaweb参考资料大全
    Java基础知识总结写代码:1,明确需求。我要做什么?2,分析思路。我要怎么做?1,2,3。3,确定步骤。每一个思路部分用到哪些语句,方法,和对象。4,代码实现。用具体的java语言代码把思路体现出来。 学习新技术的四点:1,该技术是什么?2,该技术有什么特点(使用注意):3,该技术怎么使用。demo4,该技术什么时......
  • 这些视频监控系统/安防视频监控平台EasyCVR基础知识,你都掌握了吗?
    安防视频监控平台EasyCVR是一个具有强大拓展性、灵活的视频能力和轻便部署的平台。它支持多种主流标准协议,包括国标GB28181、RTSP/Onvif、RTMP等,还可以支持厂家的私有协议和SDK接入,例如海康Ehome、海大宇等设备的SDK。该平台不仅拥有传统安防视频监控的功能,还具备接入AI智能分析的......
  • 网络编程基础知识
    一、计算机网络由2台或更多计算机组成的网络。在同一个计算机网络下,不同的计算机可以直接进行通信,是因为:不同的计算机具有相同的网络号:会被认为在同一个计算机网络下,网络号是IP地址通过子网掩码过滤后得到的(IP是101.202.99.2,子网掩码是255.255.255.0,网络号是10......
  • Java基础知识29--主线程、子线程执行顺序
    1、主线程与子线程互不影响最常见的情况,主线程中开启了一个子线程,开启之后,主线程与子线程互不影响各自的生命周期,即主线程结束,子线程还可以继续执行;子线程结束,主线程也能继续执行。publicclassTestThread{publicstaticvoidmain(String[]args)throwsInterruptedExcepti......