概述随着现代JavaScript的Web应用程序开发变得复杂,命名冲突和依赖性变得难以处理,因此需要模块化。模块化的引入可以避免命名冲突,方便依赖管理,提高代码的复用性和可维护性。因此,在JavaScript没有模块功能的前提下,只能通过第三方规范实现模块化:CommonJS:Synchronousmoduledefinitions,用于服务端。AMD:AsynchronousModuleDefinition,用于浏览器端。CMD:异步模块定义,在浏览器端使用。UMD:统一定义COmmonJS和AMD模块化方案。它们都是基于JavaScript的句法和词法特征的“假”模块式行为。TC-39在ECMAScript2015中加入了模块规范,简化了上面介绍的模块加载器。Native意味着它可以取代上述规范,成为浏览器和服务器的通用模块解决方案,比使用库更高效。而ES6的模块化设计目标:像CommonJS一样简单的语法。模块必须是静态结构。它支持模块的异步加载和同步加载。服务端和客户端均可使用,支持模块加载的“灵活配置”,更好地支持模块间的循环引用。具有语言级别的支持,超越CommonJS和AMDECMAScript于2015年开始支持模块标准,此后逐渐发展,目前已被各大浏览器所支持。ECMAScript2015版本也称为ECMAScript6。模块ES6模块借鉴了CommonJS和AMD的许多不错的特性,如下所示:模块代码仅在加载后执行。模块只能加载一次。模块是单例的。模块可以定义其他模块可以观察和交互的公共接口。模块可以请求加载其他模块。支持循环依赖。ES6模块系统也增加了一些新的行为。ES6模块默认以严格模式执行。ES6模块不共享全局命名空间。this在模块顶层的值是未定义的;楷书是窗口。模块中的var声明不会添加到window对象中。ES6模块是异步加载和执行的。当浏览器运行时知道一个文件应该被视为一个模块时,它会根据上面描述的ES6模块行为有条件地施加限制。与标签中加入type="module"属性,声明标签的顺序绑定,模块也不会等待文档完成解析后再执行。但是,入口模块必须等待其依赖项被加载。为了支持ES6模块,WorkerWorker可以在Worker构造函数中接收第二个参数。它的type属性默认值为classic,type可以设置为module来加载模块文件。如下://第二个参数默认为{type:'classic'}constscriptWorker=newWorker('scriptWorker.js');constmoduleWorker=newWorker('moduleWorker.js',{type:'module'});在基于模块的worker中,self.importScripts()方法通常用于在基于脚本的worker中加载外部脚本,调用它会抛出错误。这是因为模块的导入行为包括importScripts()。向后兼容如果浏览器本身支持ES6模块,则可以直接使用,而不支持的浏览器可以使用第三方模块系统(System.js)或在构建时翻译ES6模块。可以使用type="module"属性指定脚本模块,对于不支持模块的浏览器,可以使用nomodule属性。该属性告诉支持ES6模块的浏览器不要执行该脚本。不支持模块的浏览器无法识别并忽略此属性。如下://支持模块的浏览器会执行这个脚本//不支持模块的浏览器不会执行这个脚本//支持的浏览器moduleswillnotexecutethisscript//不支持modules的浏览器会执行这个脚本而AMD这两个模块加载器,重新定义了模块功能,整合了两个规范,并通过简单的语法声明将它们暴露出来。模块使用不同的方式加载.js文件,这与脚本完全不同:模块始终使用usestrict强制执行严格模式。在模块的顶级范围内创建的变量不会自动添加到共享全局范围内,它们只存在于模块的顶级范围内。this在模块顶级范围内的值是未定义的。模块不允许在代码中使用HTML样式的注释。对于模块外部代码可以访问的内容,模块必须导出它们。允许模块从其他模块导入绑定。模块代码执行一次。导出创建一次,然后在导入之间共享。浏览器对原生模块的支持越来越好,同时也提供了从不支持过渡到ES6模块的强大工具。更多内容请关注公众号《海人的故事》
