模块化
1、NODEJS的common.js规范
1.1、module.exports
module.exports是node的私有的一个全局变量属性,测试发现可以用require引用,也可以用import from来使用。
//demo.js
let a= "字符串";
function func() {
console.log("函数")
}
module.exports = {
a,
func
}
//module2
import util from './demo'
//let util=require('./demo')
//import {a,func} from './demo'
console.log(util)
/**
结果:
{
a:"字符串",
func:function(){
console.log("函数")
}
}
*/
1.2、exports
exports只是module.exports的全局引用 , 值得注意的是,你不能给exports赋值,这很重要,很重要,很重要。
//demo.js
// 错误写法
// exports={a:"aa"}
// 打印 {}
// 正确写法
exports.a = 10;
exports.func=function() {
console.log("lalala")
}
// 打印 {a:10,func:function}
// 上面写了exports就不能写下面的module.exports,下面会覆盖上面的,因为exports指向module.exports
// module.exports = {a:"aaa"}
//main.js 引入,下面两种都可以
//第一种
import a from './demo'
//第二种
let a=require('./demo')
2、es6 module
2.1、export
- 基本使用
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
// demo.js 第一种写法
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
export function multiply(x, y) {
return x * y;
};
//使用,需要哪个变量直接使用就好
import {firstName,year} from './demo'
console.log(firstName,year)
//打印
Michael 1958
2.2、注意点
2.2.1、import引入注意事项
上面代码的import
命令,用于加载demo中输入变量。import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js
)对外接口的名称相同。
注意,
import
命令具有提升效果,会提升到整个模块的头部,首先执行。
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名。
import { lastName as surname } from './profile';
像获取一个对象的形式获取
//错误
import utils from './demo' //utils为undefined
//正确,util可以自己更改命名
import * as util from './demo'
由于import
是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 报错
import { 'f' + 'oo' } from 'my_module';
// 报错
let module = 'my_module';
import { foo } from module;
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
}
会执行,但不会有任何结果
import 'lodash';
2.2.2、export导出注意事项
// 报错
export 1;
// 报错
var m = 1;
export m;
// 正确写法一
export var m = 1;
// 正确写法二
var m = 1;
export {m};
// 正确写法三
var n = 1;
export {n as m};
// 报错
function f() {}
export f;
// 正确
export function f() {};
// 正确
function f() {}
export {f};
2.2.3、动态变化数值
export
语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
会自动变化
//demo.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
//main.js
import {foo} from './demo'
console.log(foo) //第一次打印为bar
setTimeout(()=>{
console.log(foo) //第二次打印为baz
},1000)
2.2.4、export出现位置
export
命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,下一节的import
命令也是如此。这是因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷
// 报错
function foo() {
export default 'bar' // SyntaxError
}
foo()
//报错
{
export let a=10;
}
2.3、export default
export default
命令只能输出一个
从前面的例子可以看出,使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default
命令,为模块指定默认输出。
// 第一组
export default function suibian() { // 输出
// ...
}
import crc32 from 'crc32'; // 输入
// 第二组
export function crc32() { // 输出
// ...
};
import {crc32} from 'crc32'; // 输入
3、webpack 之 require.context 用法
最近项目中用到了vue-element-admin当作框架,当中有一个很好的例子:封装了一个svg的组件,其中就是用到了require.context
3.1、基本语法
require.context有三个参数:
directory:说明需要检索的目录
useSubdirectories:是否检索子目录
regExp: 匹配文件的正则表达式
require.context("./test", false, /\.test\.js$/);
//(创建了)一个包含了 test 文件夹(不包含子目录)下面的、所有文件名以 `.test.js` 结尾的、能被 require 请求到的文件的上下文。
require.context("../", true, /\.stories\.js$/);
//(创建了)一个包含了父级文件夹(包含子目录)下面,所有文件名以 `.stories.js` 结尾的文件的上下文。
封装svg里面用到的
//第一种用法
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
//第二种用法
const context = require.context("./svg", true, /\.svg$/)
context.keys().map(context)
4、参考链接
手摸手,带你优雅的使用 icon https://juejin.im/post/59bb864b5188257e7a427c09