深入探究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版)

Android编程权威指南(第3版)

比尔·菲利普斯 (Bill Phillips)、克里斯·斯图尔特 (Chris Stewart)、克莉丝汀·马西卡诺 (Kristin Marsicano) / 王明发 / 人民邮电出版社 / 2017-6 / 129.00元

Big Nerd Ranch 是美国一家专业的移动开发技术培训机构。本书主要以其Android 训练营教学课程为基础,融合了几位作者多年的心得体会,是一本完全面向实战的Android 编程权威指南。全书共36 章,详细介绍了8 个Android 应用的开发过程。通过这些精心设计的应用,读者可掌握很多重要的理论知识和开发技巧,获得宝贵的开发经验。 第3 版较之前版本增加了对数据绑定等新工具的介......一起来看看 《Android编程权威指南(第3版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器