JavaScript模块管理

JavaScript的模块管理

随着JavaScript的壮大,模块化是一个自然的趋势,我们可以通过模块来调用别人的代码。

首先想到的就是把同一个模块属性和方法收集到同一个对象中,
比如:

const module = {
	a:1,
	b:function(){
		console.log('xxx')
	}
}
// 还有个叫法,叫做命名空间
const nameSpace = {};
nameSpace.a = 12;

这种做法把相关的数据以及方法收集到了一块,同时也减少了对全局变量的污染,但是并没有实现真正的封装,外部依然可以访问到其内部的属性和方法。
为了达到封装的目的,然后就有了立即执行函数的写法(IIFE)

 var module = (function(){
    var a = 0;
    var m1 = function(){
      console.log('xx')
    };
    return {
      m1 ,
    };
  })();

这种写法实现了内部的封装,只暴露需要暴露的属性以及方法,同时可以通过函数参数给模块内部传递需要的信息。

CommonJS

node.js的模块系统就是按照CommonJS 实现的。
require/exports用法只有下三种,

// 导入
const fs = require('fs'); // require 的时候加载的就是导出方的module.exports对象。
// 导出
exports.fs = fs;
module.exports = fs;

node目前默认采用的就是这种模块系统。
nodejs 也可以使用ES module 其中一种方法是,把文件后缀名修改为.mjs,或者修改package.json中的type

  默认exports 是一个对象,在导出文件中exports是module.exports的引用,两者指向的内存指针是相同的。相当于文件开头有默认的一行

var exports = module.exports;

所以我们可以直接给module.exports赋值,但是不能给exports直接赋值,如果直接给exports赋值,exports和module.exports指向的地址不再相同了,两者失去了联系,require加载的时候是看不到exports的,只能看到module.exports。

exports 和 module.exports 的使用:
如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports。

//test.js
exports.number =  33;
// 效果和上面写法相同
//module.exports = {
//  number: 33
//};

// index.js
const test = require('./test.js')
console.log(test);

执行node index.js,输出:

{number:33}

将test.js修改为

// test.js
exports = {
  number: 33
};

执行node index.js,输出:

{}

  exports或者说module.exports虽然默认是一个对象,但它可以导出所有的类型的,我们可以给module.exports赋值字符串,函数等等。每个模块的变量是私有的,它由node包装在一个函数中。
  require是运行时加载,即读取并执行这个文件然后返回它的module.exports。多次引入同一个文件,只会在第一次加载的时候执行一次。再次加载就会直接返回缓存的结果。require.cache中保存着缓存的模块。

所以require可以用在文件中任何地方,只是大多写在文件头部。
当我们想单独导出其中一个方法的时候会这样写。

const {number} = require('./test.js');

  但是实际上babel把ES6转换为ES5的时候,转换后的代码可以看作下面的代码,所以还是导入了整个文件。

const _test = require('./test.js');
const number = _test.number;

打包的时候的会遇到的问题,
这也是一些UI组件需要使用babel-plugin-component的原因。

CommonJS 导出的是值的拷贝,所以在模块外部修改数据是不会影响模块内部的数据的(引用类型除外)。

ES6的module

webpack只是支持ES6的module模块系统,并不会转换ES6的所有语法。

import/export的用法有

// 导出
export default fs; //  默认导出对象
export const fs; // 导出 fs
export function readFile;
export {readFile read}
export * from fs;

// 导入
import fs from 'fs';    // 引入默认的导出对象  
import { default as fs } from 'fs'; // 同上
import * as fs from 'fs'; // 引入所有的导出对象赋值给fs
import {readFile} from 'fs'; // 引入指定的对象 
import {readFile as read} from 'fs'; // 引入指定对象并赋值给read
import fs,{readFile} from 'fs'; // 引入默认的导出对象并引入指定对象

import { number } from './test.js'

import 会先用babel转换转换为 CommonJS, 即

const _test = require('./test.js');
const number = _test.number;

此时还是导入了整个文件,也必须使用babel-plugin-component。
或者我们可手动关闭babel的模块转换,由webpack直接使用ES6,这样同时还可以使用tree-skaking功能了。

  webpack2 开始引入 tree-shaking ,通过分析ES6的语法,可以删除没有使用的模块。只对ES6语法有效。

ES6 module导入的是值的引用。导入的值不能进行修改,是只读状态,被导入的文件中对值的修改会反映到外部。

import 是静态的,只能声明在文件的顶部,不能动态导入

// 导出  export.js
export * from './pkg';
const am = 12;
export default '22'; //  默认导出对象
export const ui = 12; // 导出 fs
export function readFile(){};
export {am};

//
import xx from 'export'; // xx = 12
import {default as xx} from 'export'; // xx = 12
import * as xx from 'export' // xx = {am:12,default:12,ui:12,readFile(){}...还有pkg里面的导出};
import {am} from 'export'; // xx = 12;


总结下

CommonJS 使用的是动态导入执行的时候引入。
ES module 则是静态引入,在编译的时候引入,支持静态分析,支持tree-shaking,最终也会支持动态引入的。同时ES module 模块的代码默认进入严格模式。

深入浅出 ESM 模块 和 CommonJS 模块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值