前端的发展总会让咱们眼前一亮,这又有什么规范出来了,上个规范我还没理解透彻呢。但无论将来怎么发展,了解历史仍是很是重要的, 以史为镜,能够知得失。知道了规范的发展历史,才能更好的了解目前的规范。
看着上面的script标签,是否是有一种很熟悉的感受。经过script引入你想要的资源,从上到下的顺序,这其中顺序是很是重要的,资源的加载前后决定你的代码是否可以跑的下去。固然咱们尚未加入defer和async属性,否则加载的逻辑会更加复杂。这里引入的资源仍是算少的,过多的script标签会形成过多的请求。同时项目越大,到最后依赖会愈来愈复杂,而且难以维护,依赖模糊,请求过多。全局污染的可能性就会更大。那么问题来了,如何造成独立的做用域?前端
defer要等到整个页面在内存中正常渲染结束(DOM 结构彻底生成,以及其余脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本之后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,若是有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。
当即执行函数(immediately-invoked function expression),简称IIFE,实际上是一个javaScript函数。能够在函数内部定义方法以及私有属性,至关于一个封闭的做用域。例以下面的代码:java
let module = (function(){ let _private = 'myself'; let fun = () =>{ console.log(_private) } return { fun:fun } })() module.fun()//myself module._private//undefined
以上代码即可以造成一个独立的做用域,必定程度上能够减小全局污染的可能性。这种写法但是现代模块化的基石。虽然可以定义方法,可是不能定义属性,这时候各类前端规范就陆续登场了。node
最早遵照CommonJS规范是node.js。此次变革让服务端也能用js爽歪歪的写了,咱们的javaScript并不止于浏览器,服务端也能分一杯羹,被人称为模块化的第一座里程碑。想一想长征二万五,第一座里程碑在哪里?webpack
// 删除指定模块的缓存 delete require.cache[moduleName]; // 删除全部模块的缓存 Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; })
exports只是一个变量,指向module.exports,也就是exports只是一个引用而已。因此对外输出模块的时候,咱们就能够经过exports添加方法和和属性。经过module.exports对外输出其实也是读取module.exports的变量。可是使用exports时要很是的当心,由于稍不注意就会切断和module.exports的联系。例如:git
exports = function(x) {console.log(x)};
上面的代码运行以后,exports再也不指向module.exports。若是你难以区分清楚,通常最好就别用exports,只使用module.exports就行。es6
require.mainAPI就有这样的做用,若是模块是直接执行,那么这时require.main属性就指向模块自己。例以下面:github
require.main === module
咱们知道客户端(浏览器)加载资源主要是经过网络获取,通常本地读取的比较少,而node.js主要是用于服务器编程,模块文件通常都存在于本地硬盘上,而后I/O读取是很是快速的,因此即便是同步加载也是可以适用的,而浏览器加载资源必须经过异步获取,好比常见的ajax请求,这时候AMD规范就很是合适了,能够异步加载模块,容许回调函数。web
每一个规范的兴起背后总有一些缘由,requirejs的流行是由于commonjs未能知足咱们须要的效果,sea.js被创造的缘由也是由于requirejs不能知足一些场景。ajax
- | AMD | CMD |
---|---|---|
原理 | define(id ?,dependencies ?,factory)定义了一个单独的函数“define”。id为要定义的模块。依赖经过dependencies传入factory是一个工厂参数的对象,指定模块的导出值。 | CMD规范与AMD相似,并尽可能保持简单,可是更多的与common.js保持兼容性。 |
优势 | 特别适用于浏览器环境的异步加载 ,且能够并行加载。依赖前置,提早执行。 定义模块时就能清楚的声明所要依赖的模块 | 依赖就近,延迟执行。 按需加载,须要用到时再require |
缺点 | 开发成本较高,模块定义方式的语义交为难理解,不是很符合经过的模块化思惟方式。 | 依赖SPM打包,模块的加载主观逻辑交重。 |
体现 | require.js | sea.js |
ES6的模块不是对象,import语法会被JavaScript引擎静态分析,请注意,这是一个很重要的功能,咱们一般使用commonjs时,代码都是在运行时加载的,而es6是在编译时就引入模块代码,固然咱们如今的浏览器尚未这么强大的功能,须要借助各种的编译工具(webpack)才能正确的姿式来使用es6的模块化的功能。也正由于可以编译时就引入模块代码,因此使得静态分析就可以实现了。express
若是可以静态化,编译的时候就能肯定模块的依赖关系,以及输出和输入的变量,而后CommonJS和AMD以及CMD都只能在运行代码时才能肯定这些关系。
好比navigator如今是全局变量,之后就能够模块化加载。这样就再也不须要对象做为命名空间。
function fun(){ export default 'hello' //SyntaxError }
fun() import {fun} from 'myModule';
上面的代码import的执行早于fun调用,缘由是import命令是编译阶段执行的,也就是在代码运行以前。
export default就是输出一个叫default的变量或方法,而后系统容许你为它取任意名字。因此,你能够看到下面的写法。
//modules.js function add(x,y){ return x*y } export {add as default}; //等同于 export default add; //app.js import {default add foo} from 'modules'; //等同于 import foo from 'modules'
这是由于export default命令其实只是输出一个叫作default的变量,因此它后面不能跟变量声明语句。
利用顶层的this等于undefined这个语法点,能够侦测当前代码是否在 ES6 模块之中。
const isNotModuleScript = this !== undefined;
若是大神您想继续探讨或者学习更多知识,欢迎加入QQ或者微信一块儿探讨:854280588![]()
![]()