一、模块化
1、没有模块化的时候
xiaoming/index.js
// 我们把它写到函数里面,函数有自己的作用域
// function foo() {
// var name = "why";
// var isFlag = false;
// }
// foo();
// 但是上面的写法还要写foo()执行它,自执行函数可以替换
var moduleA = (function () {
var name = "chen";
var isFlag = true;
// 把对象返回出去,使用变量接收
return {
name: name,
isFlag: isFlag,
};
})()
xiaoming/chen.js
(function () {
if (moduleA.isFlag) {
console.log("我的名字是" + moduleA.name);
}
})()
xiaohong/index.js
(function () {
var name = "chen";
var isFlag = false;
})()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./xiaohong/index.js"></script>
<script src="./xiaoming/index.js"></script>
<script src="./xiaoming/chen.js"></script>
</body>
</html>
2、CommonJS - module.exports导出方式*
chen.js
const name = "chen123";
const age = 23;
function sum(num1, num2) {
return num1 + num2;
}
// 导出
// 导出方案: 1、module.exports
// module本身也是一个对象,exports也是
module.exports = {
aaa: "aaaa",
bbb: "bbb",
name: name,
age: age,
sum: sum,
// es6增强写法:
// name, age,sum
};
// 导出方案: 2、exports
main.js
// 使用另一个模块导出的对象,那么就需要进行导入 require,函数可以跟不同的参数
const chen = require("./chen.js"); //require后面跟路径, 这个require函数会返回一个对象
const { aaa, bbb } = require("./chen.js"); // 返回的是一个对象,可以结构
console.log(chen.aaa);
console.log(aaa);
console.log(bbb);
console.log(chen.name);
console.log(chen.age);
console.log(chen.sum(20, 30));
3、CommonJS内部原理
他们是同一个对象, 三个引用指向同一个对象
chen.js
const info = {
name: "chen",
age: 23,
foo: function () {
console.log("foo函数~");
},
};
setTimeout(() => {
info.name = '天选之子'
}, 1000)
module.exports = info;
main.js
const chen = require('./chen.js');
console.log(chen);
setTimeout(() => {
console.log(chen);
}, 2000)
3、exports导出方式
chen.js
const name = "chen123";
const age = 23;
function sum(num1, num2) {
return num1 + num2;
}
// exports源码里面是这么实现的
// module.exports = {};
// exports = module.exports;
// 第二种导出方式
exports.age = age;
exports.name = name;
exports.sum = sum;
// 最终导出的一定是module.exports
// 下面的写法是无法导出的
// exports = {
// name: name,
// age: age,
// };
main.js
const chen = require('./chen.js');
console.log(chen.name);
console.log(chen.age);
console.log(chen.sum);
4、require查找规则
// 情况一:核心模块, node模块path
const path = require("path");
path.resolve();
// 情况二:路径。如果是文件夹,会使用文件夹/index.js
require("./abc");
// 情况三:不是核心模块也不是路径
const chen = require("chen"); // 查找的是main.js所在目录下面的node_modules
// console.log(module.paths);
5、模块加载细节
6、CommonJS弊端
二、ES Module 及原理
1、ES Module基本使用**
**三种导入跟三种导出**
foo.js
// 第二种方式: export 导出 和 声明分开
const name = "chen123";
const age = 23;
function foo() {
console.log("foo function");
}
// export {} 这里不是对象,{}是语法。
export {
name,
age,
foo,
// 不能这么写: name: name
};
// 第三种方式: 第二种导出时起别名
export {
name as fName,
age as fAge,
foo as Ffoo,
};
main.js
// 1、导入方式一:普通的导入
// import { name, age, foo } from "./foo.js";
// import { fName, fAge, Ffoo } from "./foo.js";
// console.log(name);
// console.log(age);
// 2、导入方式二:起别名
// import { name as fName, age as fAge, foo as ffoo } from "./foo.js";
// 3、导入方式三:将导出的所有内容放到一个标识符中
import * as foo from "./foo.js";
console.log(foo.name);
console.log(foo.age);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 这里会被当前普通的js,不允许里面有import。我们必须加上type属性,说明这是一个模块 -->
<script src="./main.js" type="module"></script>
</body>
</html>
注意:
2、ES Module结合使用**
format.js
function timeFormat() {
return "2022-02-10";
}
function priceFormat() {
return "222";
}
export { timeFormat, priceFormat };
math.js
function add(num1, num2) {
return num1 + num2;
}
function sub(num1, num2) {
return num1 - num2;
}
export { add, sub };
index.js
// 1、导出方式一:
// import { add, sub } from "./math.js";
// import { priceFormat, timeFormat } from "./format.js";
// export {
// add,
// sub,
// priceFormat,
// timeFormat
// }
// 2、导出方式二:
// export { add, sub } from "./math.js";
// export { priceFormat, timeFormat } from "./format.js";
// 2、导出方式三:
export * from "./math.js";
export * from "./format.js";
main.js
import { add, sub, priceFormat, timeFormat } from "./utils/index.js";
const sum = add(1,30)
console.log(sum);
3、ES Module - Default**
foo.js
const name = "chen";
const age = 23;
const foo = "foo value is";
// 1.默认导出的方式一:
// export { name, age, foo as default };
// 2、默认导出的方式二: 常见
export default foo;
main.js
// export{} 导出,这里的名字必须和导出的一致,name,age
// import { name, age } from "./foo.js";
// 导入语句: 导入的是默认的导出
import chen from './foo.js'
console.log(chen);
// 注意: 默认导出只能有一个
4、ES Module - import函数
foo.js
const name = "chen";
const age = 23;
const foo = "foo value is";
export { name, age, foo };
main.js
// 这种是同步代码,如果不想解析完解析完,不阻塞后面的代码,可以当成函数使用
// import { name, age, foo } from "./foo.js";
// import 函数返回的是一个Promise。整个代码是异步的,不会影响后面代码的运行
import('./foo.js').then(res => {
// 拿到的res,其实就是整个的{ name, age, foo }
console.log(res, res.age);
})
// console.log(name);
// 在import导入之前,后面的代码是不会执行的,相当与同步的代码
console.log("后续的代码");
// ES11新增的特性
// meta属性本身就是一个对象,{url: '当前模块所在的路径'}
console.log(import.meta);