前言
在学习node.js之前,先得了解一个东西:CommonJS。CommomJS规范的目标是为了构建js在包括Web服务器,桌面,命令行工具,及浏览器方面的生态系统。
可以说CommonJS是为了解决js没有模块系统、没有标准接口等问题的一些规范。而node.js就是这些规范的一种实现。本文主要记录下个人对node.js中 module的一些认知和尝试。
Module 概念
模块化的意思大体可以解释为把具有类似功能特性的代码进行拆分,变成一个个拥有独立功能的模块。进而解决传统前端在模块化中难以解决两个重要问题:
- 冲突:不同js文件中除非将所有的变量和函数用命名空间单独包起来,不然每一个js文件中定义的变量和函数都是全局的。可能存在命名等一系列的冲突;
- 依赖:不同的js文件在加载时存在一定的先后顺序,这种先后取决于它们之间的依赖关系,有可能存在相互均存在依赖关系,无法决定加载顺序的情况。
常规Module
module.exports和require
在node.js中,会为每一个模块创建了一个模块对象:module,该对象提供了和当前模块有关的细节信息,其中有一个属性 exports,
module.exports = { },他的值是一个对象,模块内部的数据对外提供访问接口都是通过该对象来进行的。
同时还提供了一个函数:require(),其参数为所加载模块的相对路径。通过该方法来加载指定模块,该函数的返回值是被加载模块的 module.exports对象。
下面代码演示require和module.exports的关系,n1和n2为同一目录下的两个js文件:
//n1:
var a = 20;
var n2 = require('./n2.js');
console.log(n2.a);
console.log(n2);
//n2:
var a = 10;
var b = 100;
module.exports.n = a;
在node下编译得到console的结果为10 和{n: 10},此时b的值是不能在n1的console出来的。
由此,也可知道每个模块的内部的数据是私有的,外部不能直接访问,就算require了整个模块,没有将值赋给module.explorer也无济于事。这很好的解决了冲突问题。
而require()可以在模块中任意地方对其他模块进行加载,这便解决了传统前端的依赖问题。
上文演示过程均为文件模块(File Module),它与文件夹模块(Folder as Module)都为node用户编写的模块。通常都需要经过三个步骤:1.路径分析;2.文件定位;编译执行。
文件夹模块
文件夹模块是以文件夹的形式组织的模块,这种模块有一定的组织格式。
当我们加载的是一个文件夹模块的时候,node模块加载器会从当前目录下的 node_modules 的目录下去查找该文件夹模块,所以文件夹模块一定要存放在 node_modules 目录下,文件夹的名就是该模块的名称,找到该文件夹以后,再查找该文件夹下的package.json文件。package.json是该文件夹模块的说明配置文件。其主要内容为:
- name:模块名称
- version:模块的版本
- main:作为一个文件夹模块,该模块下会有很多的单个文件,那么在package.json文件通过main选项可以指定模块的入口文件(主文件),那么通过require加载模块的时候,加载的就是该main指定的文件
node通过 require( ) 来加载模块,如果模块的路径填写的是相对路径,那么加载的就是文件模块,如果填写的不是以相对路径开始的,那么就是文件夹模块。
举例如下:
//package.json
{
"name": "test",
"version": "1.0.0",
"main": "hello.js"
}
//hello.js
var worldModule = require('./world');
module.exports.hello = 'Hello ' + worldModule.world;
console.log(module.exports.hello);
//world.js
module.exports.world = 'world';
在node编译下,打印结果为 Hello world。
核心模块
Node提供的模块,例如http、fs等,称为核心模块也为全局模块。核心模块在node源代码编译的过程中就编译进了二进制执行文件,存放在node指定安装目录中。在Node进程启动的时候,部分核心模块就直接加载进内存中了。
如果 require 中的path参数不带相对路径,那么首先会按照文件夹模块去查找,如果文件夹模块模式下找不到,则会在核心模块目录中去查找是否存在,如果核心模块中还没有找到,则报错。
ESMAScipt Module
ECMAScript提供的模块化方案:
提供了两个语法支持模块导出与导入:
导出:
export
http://www.ecma-international.org/ecma-262/7.0/index.html#table-42
导入:
import
http://www.ecma-international.org/ecma-262/7.0/index.html#table-40