深入探究ES6之模块系统
栏目: JavaScript · 发布时间: 6年前
内容简介:在上一篇可以说ES6的正式发布(讨论了十年)是前端界翘首以盼众望所归的事,它是javascript被创建以来最重要的更新之一。而其中最重要的就是JS模块化的定义,从原生语法上支持了导入与导出模块,我们终于不再需要使用一些库(Requirejs、Seajs等)来模仿模块化了。本文不想过多介绍如何使用ES6模块的语法(比如import和export的规范),因为网络上关于这方面的介绍已经很多了,现在来说点不太常被提及但是对理解有很重要的东西。
在上一篇 《前端模块化,AMD和CMD的区别总结》 中,介绍了commonJS规范下衍生出来的AMD和CMD。多年来,前端的js代码大都是以这种方式组织起来(再早连这个都没有。。。),但是从语言设计本身的层面上讲,官方一直没有设计出javascript的模块系统,直到。。。ES6的正式发布!
可以说ES6的正式发布(讨论了十年)是前端界翘首以盼众望所归的事,它是javascript被创建以来最重要的更新之一。而其中最重要的就是JS模块化的定义,从原生语法上支持了导入与导出模块,我们终于不再需要使用一些库(Requirejs、Seajs等)来模仿模块化了。
本文不想过多介绍如何使用ES6模块的语法(比如import和export的规范),因为网络上关于这方面的介绍已经很多了,现在来说点不太常被提及但是对理解有很重要的东西。
“模块”是自动运行在严格模式下并且没有办法退出运行的JavaScript代码。模块有三个比较显著的特性:
1、在模块顶部创建的变量不会自动被添加到全局作用域(比如windows下),访问模块的变量必须通过导出的方式。
2、在模块顶部this的值是undefined。
3、模块不支持HTML的代码注释。
以上也是ES6模块区别于传统模块系统很重要的三点,而且ES6模块系统与传统模块系统更显著的一个区别是:
4、ES6的模块系统是静态解析的
举例:
if(Math.random()){ import name from './example.js' // 抛出错误 } ------------------------------------------------- let name = 'js' if(Math.random()){ export {name} // 抛出错误 } 复制代码
import和export不能在条件语句或任何动态方式中使用,原因是要让JavaScript引擎静态地确定哪些模块可以导出。
如果使用过RequireJS或者SeaJS的开发者应该深有体会,它们可没有这样的限制。 由于ES6模块的静态性,导致了一个怪异甚至让人困惑之处,先看一个例子:
//a.js let name = 'ajs'; let setName = fuction(newName) { name = newName; } export {name, setName} //b.js import {name, setName} from './a.js'; console.log(name) // 'ajs' name = 'bjs' // 抛出错误 setName('cjs') console.log(name) // 'cjs' 复制代码
b.js只是简单的引用了a.js中的值,而不能改变a.js中的值,当调用setName('cjs')时会回到a.js中去执行,并将其中的name设置为'cjs'。这说明ES6模块输出的是值的引用,与CommonJS(输出的是值的拷贝)完全不同。
至于将ES6模块系统设计成静态的原因,大家可以参考这篇文章 Static module resolution 。其中原理较为深奥,个人认为可以不求甚解。
PS:动态import(不是ES6的内容)
凡事有利就有弊,静态性的模块系统在带来一系列好处的同时,也限制了开发者对于项目灵活性的掌控。比如在某些条件语句或是用户点击触发的操作里面,动态(或者说按需)导入模块的要求就变得很迫切。不过还好,现在动态导入的提案已经存在于TC39的 第三阶段 了。
你可以这样使用:
if(Math.random()){ import('./example.js').then((M)=>{ let Mod = M.default // TODO }) } 或者 if(Math.random()){ import('./example.js').then(({setName})=>{ setName('Dynamic') // TODO }) } 甚至是这样 const locale = 'en'; import(`./utils_${locale}.js`).then( (utils)=>{ console.log('utils', utils); utils.default(); } ); 复制代码
·你可以在延迟加载、条件加载和用户操作的情景下使用动态导入
·动态import()可以在脚本的任何地方使用
·import()能够传递字符串,你可以根据你的需求构造匹配符
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Android编程权威指南(第3版)
比尔·菲利普斯 (Bill Phillips)、克里斯·斯图尔特 (Chris Stewart)、克莉丝汀·马西卡诺 (Kristin Marsicano) / 王明发 / 人民邮电出版社 / 2017-6 / 129.00元
Big Nerd Ranch 是美国一家专业的移动开发技术培训机构。本书主要以其Android 训练营教学课程为基础,融合了几位作者多年的心得体会,是一本完全面向实战的Android 编程权威指南。全书共36 章,详细介绍了8 个Android 应用的开发过程。通过这些精心设计的应用,读者可掌握很多重要的理论知识和开发技巧,获得宝贵的开发经验。 第3 版较之前版本增加了对数据绑定等新工具的介......一起来看看 《Android编程权威指南(第3版)》 这本书的介绍吧!