Nodejs的模块化

CommonJS模块规范

  • 一个js文件就是一个模块
  • CommonJS 就是一套约定标准,不是技术; 用于约定我们的代码应该是怎样的一种结构。
  • Node 采用的模块化结构是按照 CommonJS 规范。
  • CommonJS的特点:
    • 所有代码都运行在模块作用域,不会污染全局作用域。
    • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
    • 模块加载的顺序,按照其在代码中出现的顺序。
  • 模块的分类
    • 自定义模块:即我们自己写的功能模块文件。
    • 核心模块:即Node自带的功能模块,如:HTTP模块,fs模块等等。
    • 第三方模块:社区或第三方开发好的功能模块,可以直接拿回来用。
  • 模块的导入
    • 通过require("fs")来加载模块
    • 如果是第三方模块,需要先使用npm进行下载
    • 如果是自定义模块,需要加上相对路径./或者../,可以省略.js后缀,如果文件名是index.js那么index.js也可以省略
    • 模块可以被多次加载,但是只会在第一次加载

module.exports与exports

  • 载入一个模块就是构建一个 Module 实例,一个新的 JS 文件就是一个模块
  • module.exports 是用于为模块导出成员的接口。
  • 在模块的内部,module变量代表的就是当前模块,它的exports属性就是对外的接口,加载某个模块,加载的就是module.exports属性,这个属性指向一个空的对象。
  • exports是指向module.exports的引用,相当于在模块开始执行的时候进行var exports = module.exports操作。从下面的打印中可以看出,它们最初都是一个空对象{},而这两个对象实际上指向同一块内存空间,即在不改变它们指向的内存地址的前提下,它们是等价的。
console.log(exports) //{}
console.log(module) //Module {……exports: {},parent: null……}
console.log(exports === module.exports) //true
  • require引入的对象本质上是module.exports,这也意味着module.exportsexports指向的不是同一块内存时,exports的内容就会失效。
//try.js
exports = {name: "Join"}

module.exports = {name: "Bob"}
//main.js
let name = require('./try.js')
console.log(name) //{ name: 'Bob' }

require加载文件规则

  • require('../file.js'); // 上级目录下找 file.js 文件
    require('./file.js'); // 同级目录找 file.js 文件
    require('file.js'); // 同级目录找 file.js 文件
  • 加载顺序:
    • 按js文件来执行(先找对应路径当中的module.js文件来加载)
    • 按json文件来解析(若上面的js文件找不到时,则找对应路径当中的module.json文件来加载)
    • 按照预编译好的c++模块来执行(寻找对应路径当中的module.node文件来加载)
    • 若参数字符串为一个目录(文件夹)的路径,则自动先查找该文件夹下的package.json文件,然后再再加载该文件当中main字段所指定的入口文件。(若package.json文件当中没有main字段,或者根本没有package.json文件,则再默认查找该文件夹下的index.js文件作为模块来载入。)

CommonJS引入与ES6的区别

  • CommonJS是直接做一个值的拷贝操作,也就是一旦输出一个值,模块内部的变化是影响不到这个值的
//try.js
let counter = 1

let addCounter = () => {
  counter++
}

module.exports = {
  counter,
  addCounter
}
//main.js
let func = require('./try.js')

console.log(func.counter) //1
func.addCounter()
console.log(func.counter) //1
  • ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
//try.js
export let counter = 1

export let addCounter = () => {
  counter++
}
//main.js
import {counter,addCounter} from './try.js'
console.log(counter) //1
addCounter()
console.log(counter) //2
  • CommonJS模块的循环引用
    • 执行node main.js->第一行,require(a.js)
    • 进入require(a)方法:判断缓存->无->初始化一个module->将module加入缓存->执行a.js内容
    • 第一行导出a=1->第二行引入b.js
    • 执行b.js的内容,第一行导出b=11,第二行require(a.js)
    • 此时a.js是第二次调用require,判断缓存->有->继续执行b.js->第三行打印1->第四行修改b=22
    • b文件执行完毕回到a.js中->第三行打印b=22->导出a=2
    • a文件执行完毕,回到main.js中->获取a,第二行输出a=2->执行完毕
// a.js
module.exports.a = 1;
var b = require('./b');
console.log(b);
module.exports.a = 2;

// b.js
module.exports.b = 11;
var a = require('./a');
console.log(a);
module.exports.b = 22;

//main.js
var a = require('./a');
console.log(a);

Node加载

  • Node 要求使用 ES6 模块需要采用.mjs后缀文件名。也就是说,Node 遇到.mjs文件,就认为它是ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定"use strict"
  • 如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module。一旦设置了以后,该目录里面的 JS 脚本,就被解释用 ES6 Module。如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 模块脚本的后缀名都改成.cjs。如果没有type字段,或者type字段为commonjs,则.js脚本会被解释成 CommonJS 模块。
{
   "type": "module"  // 开启 ES6 Module 模式
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容