模块化Common JS 和 ES Module(export,import)

本文详细介绍了CommonJS模块化的历史、使用方式(如require和exports)、过程,以及与ESModule的区别,重点讲解了模块依赖、私有作用域和编译时/运行时加载特性。

目录

历程

1.几个函数:全局变量的污染,模块间没有联系

2.对象:暴露成员,外部可修改

3.立即执行函数:闭包实现模块私有作用域

common JS

module和Module

过程

模块依赖:深度优先遍历、父 -> 子 -> 父

导入:require

避免重复加载、循环引用:Module缓存

先加入缓存, 后执行模块内容

动态加载:任意位置,按需加载

导出

对象:exports=module.exports

非对象:module.exports

ES Module 使用

CommonJS  vs ES Module


模块化规范:一个模块=实现特定功能一组方法

全局污染:共享时,同名变量冲突

依赖管理:下层 js 能调用上层 js 的方法,但是上层 js 无法调用下层 js 的方法

历程

1.几个函数:全局变量的污染模块间没有联系

// 模块A
var ModuleA = {
  func1: function() {
    // ...
  },
  func2: function() {
    // ...
  }
};

// 模块B
var ModuleB = {
  func3: function() {
    // ...
  }
};

2.对象:暴露成员,外部可修改

后面提出了对象,通过将函数作为一个对象的方法来实现,但是这种办法会暴露所 有的所有的模块成员,外部代码可以修改内部属性的值

3.立即执行函数:闭包实现模块私有作用域

现在最常用的是立即执行函数的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染

//IIFE(立即调用函数表达式)
//创建一个私有作用域,避免变量之间的冲突。然后,通过返回一个对象或函数来暴露模块的公共部分
// 模块A
var ModuleA = (function() {
  var privateVar = "private";

  function privateFunc() {
    // ...
  }

  return {
    publicVar: "public",
    publicFunc: function() {
      // ...
    }
  };
})();

common JS

module和Module

module:在 commonjs 中每一个 js 文件都是一个单独的模块

module 上保存了 exports 等信息之外,还有一个 loaded(bool) 表示该模块是否被加载。

Module :以 nodejs 为例,整个系统运行之后,会用 Module 缓存每一个module的信息。

过程

//home.js
const sayName = require('./hello.js')
module.exports = function say(){
    return {
        name:sayName(),
    }
}
//编译进行首尾包装
(function(exports,require,module,__filename,__dirname){
   const sayName = require('./hello.js')
    module.exports = function say(){
        return {
            name:sayName(),
        }
    }
})
//包装函数
function wrapper (script) {
    return '(function (exports, require, module, __filename, __dirname) {' + 
        script +
     '\n})'
}
//runInThisContext
eavl(包装后的module)(module.exports, require, module, __filename, __dirname)

模块依赖:深度优先遍历、父 -> 子 -> 父

//a.js
const getMes = require('./b')
console.log('我是 a 文件')
exports.say = function(){
    const message = getMes()
    console.log(message)
}
//b.js
const getMes = require('./a')
console.log('我是 b 文件')
exports.say = function(){
    const message = getMes()
    console.log(message)
}
//main.js
const a = require('./a')
const b = require('./b')

console.log('node 入口文件')

const say = require('./a')
console.log('我是 b 文件')
console.log('打印 a 模块' , say)

setTimeout(()=>{
    console.log('异步打印 a 模块' , say)
},0)

exports.say = function(){
    const message = getMes()
    console.log(message)
}

导入:require

避免重复加载、循环引用:Module缓存

先加入缓存, 后执行模块内容

加载之后的文件的 module 会被缓存到 Module 上,比如一个模块已经 require 引入了 a 模块,如果另外一个模块再次引用 a ,那么会直接读取缓存值 module ,所以a中的代码只会执行一次

动态加载:任意位置,按需加载

require 本质上就是一个函数,那么函数可以在任意上下文中执行,来自由地加载其他模块的属性方法。

导出

对象:exports=module.exports

module.exports 导出的是一个对象时,对象的引用关系是被保留的,这意味着其他模块引入这个对象后,即使该对象后续被修改,其他模块也能看到这些修改。这是因为对象在 JavaScript 中是引用类型,它们的引用关系是保持的。

exports.author = '7'
exports.say = function (){
    console.log(666)
}
module.exports ={
    author:'7',
    say(){
        console.log(666)
    }
}

非对象:module.exports

在循环引用的时候,就容易造成属性丢失的情况发生

module.exports = a // 导出变量

module.exports = [1,2,3] // 导出数组

module.exports = function(){} //导出方法

ES Module 使用

特性命名导入/导出 (Named Import/Export)默认导入/导出 (Default Import/Export)
导出export const bridge = {};
export function getPlatform() {};

const bridge = {};

export default bridge;

导入import { bridge, getPlatform } from '@/path';import bridge from '@/path';
import anyName from '@/path';
一个文件的数量多个。一个模块可以有多个命名导出。

一个。一个模块只能有一个默认导出。

可和命名混合使用

导入时的名称必须严格匹配导出时的名称。可以使用 as 重命名:import { bridge as myBridge }可以任意命名。导入时使用的标识符由导入者决定。
主要用途导出一个模块的多个功能工具函数集合导出一个模块的主要功能、核心类或值。为模块提供一个“主出口”。
联想比喻像是一个工具箱,你从中拿出(导入)特定的工具扳手锤子)。像是一个产品盒子,你导入的是整个产品,不管你在收货单上叫它什么名字。
import bridge from "@/utils/JSBridgeHelper";

// JSBridgeHelper.js 可能的导出方式

// 方式1: 命名导出

export const bridge = {};
export function getPlatform() {};



// 方式2: 默认导出
export default bridge;

CommonJS  vs ES Module

特性ES Module (ESM)CommonJS (CJS)
语法(导出)exportexport defaultmodule.exports = ... 或 exports.xxx = ...
语法(导入)importconst mod = require('...')
加载方式编译时静态解析,模块的依赖关系在代码运行前就已经确定,利于 tree-shaking。

运行时动态加载

在服务器端,同步加载模块的方式是可行的,因为模块通常都在本地。

主要环境现代浏览器、新一代前端构建工具。Node.js 环境。

「万字进阶」深入浅出 Commonjs 和 Es Module - 掘金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值