文章目录
没有模块化写法的问题
在以前前后端不分离时期,都是一个html文件里引入各种js文件,这就会照成js变量污染的问题。
虽然有函数执行的方式能够一定程度避免,例如a.js文件:
let aData = (function () {
// 不想暴露到全局上的变量
let a = 1;
// 暴露给全局的变量
let b = 2;
let c = 3;
return {
b,
c,
};
})();
然后b.js文件:
(function () {
console.log("获取到a文件的变量", aData);
})();
但随着项目越来越复杂,这种方式也会渐渐力不从心的。
当工程化时代来临后,可以通过模块化的导入导出完美的解决这个问题。
ES Module写法
export的导入导出
a.js中导出:
export function a(n) {
console.dir("a" + n);
}
export function b(n) {
console.dir("b" + n);
}
export function c(n) {
console.dir("c" + n);
}
b.js中选择性引入:
import { a, b as B } from "./a.js"; // 选择性导入a,b导入后改名为B
a("可直接使用")
这种方式我觉得适合一些比较大的js库,可以引入所需部分。
b.js中全部引入:
import * as obj from "./a.js"; // 全部导出是个*表示,然后命名为obj,是个对象
obj.a("可直接使用");
export default的导入导出
a.js中导出:
export default {
a: function (n) {
console.log("a" + n);
},
b: function (n) {
console.log("b" + n);
}
};
或者
function a(n) {
console.log("a" + n);
}
function b(n) {
console.log("b" + n);
}
export default {
a, // es6的语法省略
b,
};
b.js中引入:
import utils from "./a.js"; // 默认要以对象的形式接收
utils.a("以对象的形式使用");
注意:如果项目用webpack的话,引用 ./
不能省略,因为是通过webpack来进行的编译,而webpack又是通过node写出来的,所以要遵循node的规定;
export与export default同时写
这两个可以同时出现在一个js文件中:
const obj = { a: 'a' }
export class Person {}
export default obj
默认导出的是obj,要导入Person就需要手动写:
import obj, { Person } from './index.js'
动态按需导入
没想到吧,可以按需导入:
clickFn() {
import('jquery').then(res=>{
let $ = res.default
})
}
注意哦是个异步的导入方式。
借助webpack导出
适用场景,例如一个icon文件夹中有很多名字有规律的图片:
---icon
---icon1.png
---icon2.png
...
我们可以在文件夹里建个js,然后写上:
const context = require.context('./', true, /.png$/)
let iconMap = {}
context.keys().forEach((filename) => {
iconMap[filename.slice(2, 6)] = context(filename).default
})
export default iconMap
在其他文件中导入就能获取到一个存放key为文件名,value为base64图片的对象啦。
如果出现webpack的报错,很有可能这个webpack版本不能正确解析循环引用关系,可以改写成导出函数,这个函数里循环获取文件数据并返回出。其他文件导入使用的时候再执行下这个函数就好了
注意符号绑定的特性/引用传递
假如有个js文件专门存放很多变量导出供各个组件使用,那么要注意了,当其中一个组件中修改了js文件的某个变量,这个变量在其他组件的值也会改变(无论值类型还是引用类型)。
同上,json类型的文件引入到各个组件中使用也会有这样的问题。
引用传递的解释可参考:引用传递
这种特性的说法叫符号绑定或者引用传递。
如果不想利用到这种特性,我想到两种做法:
第一:
每个变量都单独一个函数返回出来:
export function fn() {
return {
a: 1
}
}
但是这个方式麻烦就是每次都要执行一次用个变量赋值。
第二:
在引入的时候重新声明变量:
import { a } from './user.js' // 用 as 也是一样的效果
import * as obj from './user1.js'
const A = a
const { c: C } = counter; // 解构赋值
但是引用类型的话还是同一个内存
ES Module特性总结
- 符号绑定/引用传递
- 是官方的新语法标准
- 支持node和浏览器环境(node更常用的是CommonJS规范)
- 支持异步动态按需导入
commonJS模块化规范
开发重点看webpack的批量文件导出部分
具体看:【Node.js】学习系列2-commonJS的模块规范