首页 >> 大全

ES6模块化与工程化、export导出、import导入、CJS模块化、模块对象

2023-10-05 大全 25 作者:考证青年

目录

模块化与工程化

ES6模块化

导出

导入

CJS模块化

模块对象

导出

导入

差异

拓展:(授课不做要求)

path模块

模块

url模块

模块化与工程化

一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。这对开发大型的、复杂的项目形成了巨大障碍。

在 ES6 之前,社区制定了一些模块加载方案,最主要的有 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

注意:从 v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。在v12的版本里面,需要在.json中设置"type": "",

Tip:模块化是项目工程化的前提。

ES6模块化

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量

ES6 模块不是对象,而是通过命令显式指定输出的代码,再通过命令输入。上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 模块的加载方式高。

ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use ";

Tip:用来从模块中导出,用来从模块中导入。

// ES6模块使用示例
import { stat, exists, readFile } from 'fs'; 

导出

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用关键字输出该变量。命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系,也就是说外部接口需要用这个接口名来引用。

在编写文档的时候编者的node版本是v14.16.0,查看node版本使用node -v命令。

在src下创建.js文件,内部内容如下:

let firstName = 'Michael'; 
let lastName = 'vicky'; 
// 列表导出
export { firstName, lastName }; 

运行.js文件,使用node src/.js

node src/testModule.js

正常情况如下:

如果出现以下错误:

上图蓝色框中的内容就是解决该错误的方法,在.json中添加"type": "",以保证该功能正常运行。

再次执行node src/.js就可以了。

node src/testModule.js

let firstName = 'Michael'; 
let lastName = 'vicky'; 
// 列表导出
export { firstName, lastName }; 
// 重命名导出
export { firstName as first, lastName as last};
// 导出单个属性 
export let a = 3;	
// 导出一个函数
export function multiply(x, y) { return x * y; }; 
// 默认导出,一个模块只能有一个默认导出,不能使用 var、let 或 const 用于导出默认值 export default。
export default {}
export default function  foo(){}
let b = 1;
// 报错,因为没有提供对外的接口。应该export let b = 1; 或者export {b}
export b;	

需要特别注意的是,命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系,不能直接导出一个值。

导入

静态的 语句用于导入由另一个模块导出的绑定。

命令: 使用命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载,但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到 命令,为模块指定默认输出

export default function foo() { console.log('foo'); 
}

其他模块加载该模块时,命令可以为该匿名函数指定任意名字。

import customName from './export-default'; 
customName(); // 'foo’
export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能对应一个方法或者对象。

// 导入整个模块内容
import * as person from './testExport.js'	
// 导入列表内的多个接口
import {firstName,lastName} from './testExport.js'
// 重命名导入
import {firstName as name} from './testExport.js'	
// 运行整个模块而不导入任何值
import './testExport.js';   
// 导入使用export default导出的模块
import myDefault from './testExport.js';  

测试导出和导入:

在src目录下新建.js和.js两个文件,.js文件里用来测试导出,.js用来测试导入。

.js内部代码

let firstName = 'Michael'; 
let lastName = 'vicky'; 
// 列表导出
export { firstName, lastName }; 

.js内部代码

// 导入列表内的多个接口
import { firstName, lastName } from './testExport.js'
// 重命名导入
import { firstName as name } from './testExport.js'
console.log(firstName, lastName, name);
// 结果为 Michael vicky Michael

执行node src/.js命令,输出结果。

node src/testImport.js

模块化开发的优点主要有这么几点:

使用模块化开发能解决文件之间的依赖关系。

当你引入很多个JS文件的时候,很有可能会不清楚这些JS文件之间的依赖关系,从而导致加载顺序出错。使用模块化开发之后就能避免这个问题。

使用模块化开发可以避免命名的冲突。

JS本身是没有命名空间的,为了减少命名冲突,经常使用对象或者闭包来减少命名冲突。对象只能减少命名冲突的概率,闭包的过多使用会造成内存泄漏。模块化开发之后,在模块内任何形式的命名都不会和其他模块的命名产生冲突,有效的解决了命名冲突的问题。

使用模块化开发能进行代码的复用。

当我们想要实现某个功能的时候,如果某个模块正好有这个功能,我们就可以直接引用该模块,不必再写多余的代码,这样可以提高代码整体的效率,减少重复冗余的代码。

CJS模块化

(CJS) 和 AMD 模块,都只能在运行时确定模块之间的依赖关系,以及输入输出的变量。比如, 模块就是对象,输入时必须查找对象属性。

// CommonJS模块 
let { stat, exists, readfile } = require('fs');
// 等同于如下代码块
let _fs = require('fs'); 
let stat = _fs.stat;
let exists = _fs.exists; 
let readfile = _fs.readfile; 

上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。

模块化规范,服务器端工作,实现了。

模块对象

Node内部提供一个构建函数。所有模块都是的实例。每个模块内部,都有一个对象,代表当前模块。它有以下属性,通过.XXX来使用:

属性说明

id

模块的识别符,通常是带有绝对路径的模块文件名

模块的文件名,带有绝对路径

返回一个布尔值,表示模块是否已经完成加载

返回一个对象,表示调用该模块的模块

返回一个数组,表示该模块要用到的其他模块

表示模块对外输出的值

导出

为了方便,Node为每个模块提供一个变量,指向.。使用.={}或者.XXXX=""来导出。这等同在每个模块头部,有一行这样的命令:

let exports = module.exports;

导入

函数是提供的内置函数,用于加载指定路径的模块或者是指定名称的模块。将加载的模块进行返回,使用如下:

返回一个对象

let path = require('fs');

测试导出和导入:

在src下创建.js和.js文件,.js用来测试导出,.js用来测试导入。

.js文件内容如下:

// 导出
module.exports = {firstName: 'Michael',lastName: 'vicky'
};

.js文件内容如下:

// 导入
const { firstName, lastName } = require('./testExports');
console.log(firstName, lastName);

执行node src/.js命令,输出结果。

node src/testRequire.js

差异

验证导出的是值的拷贝:

//testCommonJS.js
let firstname = 'ren';
let lastname = 'terry';
setTimeout(() => {firstname = 'zhao';
}, 2000);
module.exports = {firstname: firstname,lastname: lastname// 对象属性的简写方式/* firstname,lastname */
};//useCommonJS.js
let { firstname, lastname } = require('./testCommonJS.js');
console.log(firstname, lastname);
setTimeout(() => {console.log(firstname, lastname);
}, 4000)

node src/useCommonJS.js 
ren terry
ren terry

验证ES6导出的是值引用:

//testES6.js
let firstname = 'ren';
let lastname = 'terry';
setTimeout(() => {firstname = 'zhao';
}, 2000);
export { firstname, lastname };//useES6.js
import { firstname, lastname } from './testES6.js'
console.log(firstname, lastname);
setTimeout(() => {console.log(firstname, lastname);
}, 4000);

node src/useES6.js
ren terry
zhao terry

拓展:(授课不做要求) path模块

path 模块提供了一些工具函数,用于处理文件与目录的路径,使用如下方法引用:

var path = (‘path’);

path.() 该方法返回一个参数路径的最后一部分

path.() 该方法返回一个 path 的目录名

path.() 该方法返回 path 的扩展名,即从 path 的最后一部分中的最后一个 .(句号)字符到字符串结束。

path.() 该方法会判定 path 是否为一个绝对路径。

path.join() 该方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径

path.() 该方法会规范化给定的 path,并解析 '..' 和 '.' 片段

path. 该属性提供平台特定的路径分隔符

模块

模块提供了一些实用函数,用于解析与格式化 URL 查询字符串。使用如下方法引用

var = ('');

.(obj[, sep[, eq]]) 将对象转换为查询字符串

obj 要序列化成 URL 查询字符串的对象。

sep 用于界定查询字符串中的键值对的子字符串。默认为 '&'。

eq 用于界定查询字符串中的键与值的子字符串。默认为 '='。

.parse(str[, sep[, eq]]) 将查询字符串转换为对象

url模块

url模块提供了一些实用函数,用于 URL 处理与解析。 可以通过以下方式使用

var url = ('url');

url.parse() 将一个url地址转换为一个对象

url.() 该方法会以一种 Web 浏览器解析超链接的方式把一个目标 URL 解析成相对于一个基础 URL

url.('/one/two/three', 'four'); // '/one/two/four'

url.(' ', '/one'); // '#39;

url.('#39;, '/two'); // '#39;

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了