JS基础总结(3)—— 模块

1. ES6 Module

1.1 export

export 导出模块,导出的是对象,因此当值改变后,导出内容会跟着变,一个模块可以导出多个内容

export let val = 0
setTimeout(() => {
    val = 1
}, 100)

export default 导出指定的默认输出,一个模块只允许有一个。本质是将后面跟着的值赋予default变量再导出,因此后面只能跟值或者具有值的内容,不能跟声明语句

1.2 import

import引入并执行模块,会在编译时执行,具有变量提升效果

由于编译时执行,不能使用表达式或变量

import { 'f' + 'oo' } from './test' // 报错

多次引入模块只会执行一次

import { foo } from './test' 
import { bar} from './test' 
// 等同于
import { foo, bar } from './test'

整体加载后不允许运行时修改

import * as test from './test'
test.foo = () => {} // 报错

import 无法脱离HTML运行,而require可以

import test from './test' // 当运行单个js文件时报错
let test = require('./test') // 正常导入模块

1.3 异步加载

浏览器加载script通常是同步的,在加载并执行过程中会停止渲染。这样会造成不好的用户体验,因此加入了异步加载
defer 遇到标签时开始下载,页面渲染结束后执行,多个defer能保证顺序加载
async 遇到标签时开始下载,文件下载好立马执行,多个async无法保证顺序

2. CommenJS模块

2.1 模块化问题

由于语言问题,Javascript天生不支持模块化,因此为了解决这个问题有很多方案。
浏览器中:

  1. <script>标签引用加载,必须考虑加载顺序问题
  2. require.js 第三方库AMD
  3. sea.js 第三方库CMD
    无论是CommonJSAMDCMDUMDES6 Modules都是为了解决Javascript模块化问题
    ES6 Modules是官方提供的JS模块化解决方案
    Node本身提供了模块化,并且在8.5版本后对ES6 Modules进行了支持

2.2 模块加载

  1. 模块分为核心模块和文件模块,核心模块中完全由C/C++编写的称为内建模块
  2. 优先从缓存加载模块,缓存的是编译执行之后的对象
  3. 核心模块加载最快,路径形式其次,自定义模块最慢(会逐层向上的node_modules目录中查找)
  4. 分析包时会首先以package.json文件中main属性指定的文件名为入口,如果失败则依次查找index.jsindex.jsonindex.node
  5. 模块内和模块外互不影响,无法访问除导出内容以外的一切内容

2.3 模块编译

  1. 每个文件模块都是一个对象,通过require.extensions上的方法对不同扩展名进行加载
  2. 通过在外部包装function传入require, exports, module,__filename,__dirname等变量

2.4 模块导入导出

  1. requireexports。require可以执行被加载模块中的代码并获取被导出的对象, exports可以导出模块中想要导出的内容
  2. exports是形参传入,指向module.exports,默认是空对象。Nodeexports,ES6是export
  3. ES6中export可以出现多次且每个都需要变量名,export default只能出现一次
  4. Node中实际导出的是module.exports,而exports = xxx的语法实际修改的是形参的引用,并不会影响module.exports,所以会导致结果失败

2.5 npm

npm init -y // 快速生成package.json文件
npm install --global cnpm // 全局安装cnpm
npm install jquery --regisrty=https://registry.npm.taobao.org // 不安cnpm使用淘宝镜像
npm config set registry https://registry.npm.taobao.org // 将淘宝镜像配置进文件
npm config list // 查看配置文件

2.6 package.json 和package-lock.json

  • npm 5 以前是没有 package-lock.json文件的, npm 5 以后才加入
  • package.json文件会储存项目的基本信息,npm install时会以这个文件的依赖为准下载依赖包
  • 当安装包时,npm 会生成或者更新package-lock.json这个文件
  • package-lock.json文件会保存node_modules中所有包的信息(版本,下载地址),当重新npm install时可以提升下载速度
  • package-lock.json文件可以锁定依赖版本,防止自动升级新版

3. ES6模块与CommenJS模块差异

  1. CommonJS 模块输入的是一个值的复制,ES6模块输出的是值的引用
  2. CommenJS 模块是运行时加载,ES6 模块是编译时输出接口

4. 循环引用

由于实际运用中,很难避免模块之间的互相依赖,因此模块的循环加载是必须考虑的问题

4.1 CommonJS

模块a加载时依赖模块b,停止加载模块a去加载模块b模块b中遇到加载模块a时,返回模块a已加载的部分,继续加载模块b至完成后,再返回加载模块a

扫描二维码关注公众号,回复: 10636641 查看本文章
// test.js
exports.done = false
var test2 = require('./test2')
console.log('在test中,test2.done = %j', test2.done)
exports.done = true
console.log('test执行完毕')
// test2.js
exports.done = false
var test = require('./test')
console.log('在test2中,test.done = %j', test.done)
exports.done = true
console.log('test2执行完毕')
// main.js
var test = require('./test')
var test2 = require('./test2')
console.log('执行完毕')
// 在test2中,test.done = false
// test2执行完毕
// 在test中,test2.done = true
// test执行完毕
// 执行完毕

4.2 ES6 模块

同上,依旧是模块a加载模块b模块b加载模块a时获取模块a的返回,执行完模块b后再执行模块a
区别在于:
ES6模块返回的是对象,后续的改变会影响已返回的值
CommonJS返回的是值,后续的改变不会影响已返回的值
因此如下代码,ES6可以执行,CommonJS则不行

// even.js
import { odd } from './odd.js'
export let counter = 0
export function even(n) {
	counter ++
    return n == 0 || odd(n - 1)
}
// odd.js
import { even } from './even.js'
export function odd(n) {
    return n != 0 && even(n - 1)
}
// main.js
import * as res from './even.js'
res.even(10)
console.log(res.counter) // 6
发布了6 篇原创文章 · 获赞 0 · 访问量 82

猜你喜欢

转载自blog.csdn.net/weixin_44844528/article/details/104742048