require 属于 commonJS 规范,想了解详细的,戳我;javascript
静态 import,动态 import() 属于 ES6 规范;html
require 能够引用 JS、json 等;
// test.js module.exports = { a: "china", b: function() { console.log("b"); } }; //引用 var test = require("./test"); test.b();
export 能够处处变量、对象、函数、类等
写法 1:export + 完整定义变量或者函数的表达式vue
// 变量 export var a = 10; // 函数 export function name() {} // 这种写法要求,必需要是完整定义;好比,变量要有 var、const、let字段,函数要有 function字段
错误写法:java
// 变量 表达式不完整 var a=10; export a; // 函数 表达式不完整 var name=function(){}; export name; // 对象 export { a:"name" } // 常量 export 1;
验证网址,戳我,能够验证上述 是否正确;node
写法 2:export {变量名}
针对方法 1 中的错误写法,能够以下改正:jquery
// 变量名加花括号 var a = 10; export { a }; // 函数名加花括号 var name = function() {}; export { name }; // 多个变量时 export { a, name }; // 通常JS文件,好比utils 文件,在每一个方法或者变量前加export,而不是 export {a,name}这种形式;这样写的好处,比较方便移植; export function name() {} export var a = "test";
写法 3:export default
语法糖es6
使用export default
写法,为模块指定默认输出,这样就不须要知道所要加载模块的变量名;export default
在一个 JS 文件中只能使用一次;
// 变量 var a = 10; export default a; // 函数 export default function() {} // 等效于 function fun() {} export { fun as default }; // 导出default变量以及其余变量 export { fun as default, a, name }; // 针对 export { fun as default, a, name };在utils文件中还能够 export default fun; export var a = 0; export var name = "china";
as
关键字用来取别名;加入引入多个文件,有相同的变量名,可使用使用as
关键字避免冲突
// a.js var a = function() {}; export { a as fun }; // b.js import { fun as a } from "./a"; a();
引入文件不含有export default
json
import { a, b, c } from "./a";
引入文件仅含有 export default
segmentfault
import a from "./d"; //等效于 import { default as a } from "./d";
引入文件既含有export default
,还含有其余export
设计模式
import $, { each, map } from "jquery";
import 命令会被 JS 引擎静态分析(编译阶段),先于其余模块执行;
// 报错 if (x > 2) { import a from "./a"; } ///repl: 'import' and 'export' may only appear at the top level (2:2)
上面代码中,引擎处理 import 语句是在编译时,这时不会去分析或执行 if 语句,因此 import 语句放在 if 代码块之中毫无心义,所以会报句法错误,而不是执行时错误。也就是说,import 和 export 命令只能在模块的顶层,不能在代码块之中(好比,在 if 代码块之中,或在函数之中)。
这样的设计,当然有利于编译器提升效率,但也致使没法在运行时加载模块。在语法上,条件加载就不可能实现。若是 import 命令要取代 Node 的 require 方法,这就造成了一个障碍。由于 require 是运行时加载模块,import 命令没法取代 require 的动态加载功能。
特色 1:import() 返回 promise 对象
特色 2:相较于 import 命令,import()能够实现动态加载,其路径能够根据状况改变
特色 3:import()适用在运行阶段,而不是像 import 同样在编译阶段,这意味着 import(),可使用在 JS 代码中,好比条件判断,函数中等
场景 1:按需加载
import()能够在须要的时候,再加载某个模块。vue 中异步组件的使用,也用到了 import()方法;戳这里
场景 2:条件加载
import()能够放在 if 代码块,根据不一样的状况,加载不一样的模块。
if (condition) { import('moduleA').then(...); } else { import('moduleB').then(...); }
场景 3:动态的模块路径
import()容许模块路径动态生成。
import(f()).then(...);
注意点:
import()加载模块成功之后,这个模块会做为一个对象,看成 then 方法的参数。所以,可使用对象解构赋值的语法,获取输出接口。
import("./myModule.js").then(({ export1, export2 }) => { // ...· });
上面代码中,export1 和 export2 都是 myModule.js 的输出接口,能够解构得到。
若是模块有 default 输出接口,能够用参数直接得到。
import("./myModule.js").then(myModule => { console.log(myModule.default); });
上面的代码也可使用具名输入的形式。
import("./myModule.js").then(({ default: theDefault }) => { console.log(theDefault); });
若是想同时加载多个模块,能够采用下面的写法。
Promise.all([ import('./module1.js'), import('./module2.js'), import('./module3.js'), ]) .then(([module1, module2, module3]) => { ··· });
import()也能够用在 async 函数之中。
async function main() { const myModule = await import("./myModule.js"); const { export1, export2 } = await import("./myModule.js"); const [module1, module2, module3] = await Promise.all([ import("./module1.js"), import("./module2.js"), import("./module3.js") ]); } main();
module.exports 有两种写法:
针对上述结论以及 module.exports 两种写法,做了以下测试:
// requie.js module.exports从新赋值 日期 console.log("I am require.js"); module.exports = new Date(); // index.js const t = require("./require.js"); console.log(t.getTime()); setTimeout(() => { const t = require("./require.js"); console.log(t.getTime()); }, 3000); console.log("执行页面"); // 结果: // I am require.js // 1576220112564 // 执行页面 // 1576220112564
// require.js module.exports从新赋值 对象;日期做为对象属性值 module.exports = { t: new Date() }; // index.js const { t } = require("./require.js"); console.log(t.getTime()); setTimeout(() => { const { t } = require("./require.js"); console.log(t.getTime()); }, 3000); console.log("执行页面"); // 结果: // 1576219864761 // 1576219864761
// require.js module.exports从新赋值 对象;日期赋值给变量,做为函数导出值 let t = new Date(); module.exports = { get: () => { return t; } }; // index.js const { get } = require("./require.js"); console.log(get().getTime()); setTimeout(() => { const { get } = require("./require.js"); console.log(get().getTime()); }, 3000); // 结果: // 1576219588328 // 1576219588328
// require.js module.exports做为对象,日期赋值给t属性 module.exports.t = new Date(); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 结果: // 1576228870548 // 1576228870548
// require.js module.exports做为对象;日期做为对象的值 module.exports.t = { time: new Date() }; // index.js const foo = require("./require.js"); console.log(foo.t.time.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.time.getTime()); }, 3000); // 结果: // 1576229080434 // 1576229080434
// require.js 从新赋值对象;日期在函数中运行(暴露函数) module.exports = { get: () => { return new Date(); } }; // index.js const { get } = require("./require.js"); console.log(get().getTime()); setTimeout(() => { const { get } = require("./require.js"); console.log(get().getTime()); }, 3000); // 结果: // 1576219323353 // 1576219326358
结论:上述状况总结下,require 要想不受缓存影响,把变量等定义在函数中,利用函数延迟执行的特色来解决;
--------两次导出 module.exports------------
// require.js module.exports.t = new Date(); setTimeout(() => { module.exports.t = new Date(); }, 500); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 结果: // 1576225753706 // 1576225754208
// require.js module.exports = new Date(); setTimeout(() => { module.exports = new Date(); }, 500); // index.js const foo = require("./require.js"); console.log(foo.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.getTime()); }, 3000); // 结果: // 1576226052279 // 1576226052781
// require.js module.exports = { t: new Date() }; setTimeout(() => { module.exports = { t: new Date() }; }, 500); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 结果: // 1576227838138 // 1576227838639
结论,只要是这种 module.exports 导出两次的,都不会有缓存;
针对上述结论,做了以下测试:
// import.js console.log("import 执行"); export default new Date();
<script type="module"> import a from "./import/import.js"; import z from "./import/import.js"; console.log(a.getTime()); console.log(z.getTime()); // 结果: // import 执行 // 1576478875409 // 1576478875409 </script>
console.log("import 执行"); export default new Date();
<script type="module"> var b = import("./import/import.js"); b.then(({ default: time }) => { console.log(time.getTime()); }); setTimeout(() => { var c = import("./import/import.js"); c.then(({ default: time }) => { console.log(time.getTime()); }); }, 3000); // 结果: // 调用文件执行 // import 执行 // 1576479834365 // 1576479834365 </script>
// require.js console.log("I am require.js"); module.exports.t = { time: new Date() }; // index.js const foo = require("./require.js"); console.log(foo.t.time.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.time.getTime()); }, 3000); console.log("执行页面"); // 结果: // I am require.js // 1576483718781 // 执行页面 // 1576483718781
console.log("import 执行"); export default new Date();
<script type="module"> var b = import("./import/import.js"); b.then(({ default: time }) => { console.log(time.getTime()); }); setTimeout(() => { var c = import("./import/import.js"); c.then(({ default: time }) => { console.log(time.getTime()); }); }, 3000); // 结果: // 调用文件执行 // import 执行 // 1576479834365 // 1576479834365 </script>
本身总结这篇的时候,查了很多资料,本身作了一些测试,尽可能保证所写的结论,可以获得实践的支撑,以避免贻误他人;若是文中,有哪些代码问题,或者逻辑错误,欢迎指正!
本人在平常学习中,也收集了一些有价值的资料,涉及到诸如源码、设计模式等,欢迎一块儿交流学习!
es6 import()函数
require、缓存
export MDN
NodeJS 中的 require 和 import
require,import 和 import()函数的区别
require 和 import 的区别是什么?看这个你就懂了
模块化
深刻理解 ES6 模块机制
万岁,浏览器原生支持 ES6 export 和 import 模块啦!