1. 云栖社区>
  2. PHP教程>
  3. 正文

原生ECMAScript模块(ECMAScript modules)概述

作者:用户 来源:互联网 时间:2017-12-01 14:28:30

模块ecmascript原生概述Modules

原生ECMAScript模块(ECMAScript modules)概述 - 摘要: 本文讲的是原生ECMAScript模块(ECMAScript modules)概述, 本文标签: JavaScript ECMAScript模块 ES6模块 CommonJS Safari技术 服务器 2016年浏览器和Node.js对于ECMAScript 2015 specification的应用取得了难以置信的发展。

本文标签: JavaScript ECMAScript模块 ES6模块 CommonJS Safari技术 服务器


2016年浏览器和Node.js对于ECMAScript 2015 specification的应用取得了难以置信的发展。现在我们面临的状况是支持情况几乎都接近100%:


原生ECMAScript模块(ECMAScript modules)概述-


但是标准也同时介绍了ECMAScript modules(今天也经常被叫作ES或者ES6模块)。它仅仅是会(并且会继续)花最多的时间来实现这一标准,因为还没有浏览器在稳定版本中实现。 最近 Safari 10.1 (Safari Beta), Firefox 54 (Nighly) 以及Edge 15 (next EDGE version)或在之后的标志下 即将实现原生的开箱即用,因此我们很快就可以不需要模块打包来实现。 为了更好地了解我们如何来到这一点,让我们从JS模块历史开始,然后看看当前Native ES模块的特性和实现。


历史

历史上JavaScript没有提供模块系统。有很多技术,我主要说一下最典型的: 1)script标签里面的长脚本 E.g.:



1


2



2) 使用script标签逻辑地将文件进行划分:



1
/* js */

2
3
// module1.js

4
// module1 code

5
6
// module2.js

7
// module2 code

1


2


3



3) 模块作为一个函数(一个模块就是一个返回自我调用函数或者JavaScript构造函数的函数)

应用程序文件/模型作为应用程序的入口点:
01
// polyfill-vendor.js

02
(function(){

03
// polyfills-vendor code

04
}());

05
06
// module1.js

07
function module1(params){

08
// module1 code

09
return module1;

10
}

11
12
// module3.js

13
function module3(params){

14
this.a = params.a;

15
}

16
17
module3.prototype.getA = function(){

18
return this.a;

19
};

20
21
// app.js

22
var APP = {};

23
24
if(isModule1Needed){

25
APP.module1 = module1({param1:1});

26
}

27
28
APP.module3 = new module3({a: 42});

1


2


3


4


5



之后社区发明了真正的分离技术来继续这种分离。主要的想法是提供一个系统,它将允许你只是包括一个链接到JS文件,如:html和其他一切都在bundler端。


让我们来看看主要的JavaScript模块技术标准:


异步模块定义(AMD)

这个方法与RequireJS库以及工具(如r.js)来构建结果打包。常用的语法是:



01
// polyfill-vendor.js

02
define(function () {

03
// polyfills-vendor code

04
});

05
06
// module1.js

07
define(function () {

08
// module1 code

09
return module1;

10
});

11
12
// module2.js

13
define(function (params) {

14
var a = params.a;

15
16
function getA(){

17
return a;

18
}

19
20
return {

21
getA: getA

22
}

23
});

24
25
// app.js

26
define(['PATH/polyfill-vendor'] , function () {

27
define(['PATH/module1', 'PATH/module2'] , function (module1, module2) {

28
var APP = {};

29
30
if(isModule1Needed){

31
APP.module1 = module1({param1:1});

32
}

33
34
APP.module2 = new module2({a: 42});

35
});

36
});


CommonJS

它是Node.js生态系统中的基础JS打包。Browserify是使用它作为构建的主要工具之一。本标准的显著特点是为每个模块提供一个单独的作用域。 如下所示:



01
// polyfill-vendor.js

02
// polyfills-vendor code

03
04
// module1.js

05
// module1 code

06
module.exports= module1;

07
08
// module2.js

09
module.exports= function(params){

10
const a = params.a;

11
12
return {

13
getA: function(){

14
return a;

15
}

16
};

17
};

18
19
// app.js

20
require('PATH/polyfill-vendor');

21
22
const module1 = require('PATH/module1');

23
const module2 = require('PATH/module2');

24
25
const APP = {};

26
27
if(isModule1Needed){

28
APP.module1 = module1({param1:1});

29
}

30
31
APP.module2 = new module2({a: 42});


ECMAScript模块 (aka ES6/ES2015/Native JavaScript modules)

另外一个标准是ES2015。它带来了社区需要的语法和功能。

单独的模块作用域
默认strict模式
循环依赖
你可以轻松地按照规范拆分代码 有一些加载器/编译器/方法支持系统中的一部分或者全部,例如:

Webpack


SystemJS


JSPM


Babel


UMD

工具

对于今天,我们习惯使用工具来打包JavaScript模块。如果我们谈论到ECMAScript,您可以使用以下方法之一:

Rollup


Traceur Compiler


Babel,特别的ES2015 modules to CommonJS transform插件


Webpack 2也带来了Tree Shaking (删除未使用的引入)

通常该工具提供CLI和或或者配置和打包JS文件的能力。它获取入口点并且打包您的文件,通常加入use strict以及某些为了让代码在所有环境(老版本浏览器,Node.js等等)而对单吗进行转换。 让我们看看简化的Webpack配置,它设置了入口点并且使用Babel来处理JS文件:



01
// webpack.config.js

02
const path = require('path');

03
04
module.exports = {

05
entry: path.resolve('src', 'webpack.entry.js'),

06
output: {

07
path: path.resolve('build'),

08
filename: 'main.js',

09
publicPath: '/'

10
},

11
module: {

12
loaders: {

13
"test": //.js?$/,

14
"exclude": /node_modules/,

15
"loader": "babel"

16
}

17
}

18
};


配置的主要意思是: 1. 从webpack.entry.js文件启动


2. 对于所有的JS文件应用Babel加载器(意味着代码将根据预置/插件+bundled来进行转化)


3. 将结果放入main.js文件


在这种情况下,通常index.html包含以下内容:



1



那么你的app使用的是打包以及转换后的JS代码。上述是使用打包的常见方法,接着让我们看看如何在浏览器中不使用打包来进行模块划分。


如何使JavaScript模块在浏览器中工作
浏览器支持

现如今,每个主流浏览器都在向支持ES6模块发展:

Firefox-实现,在Firefox 54+中的标志下可用


Chrome-正常工作


EDGE-实现,在EDGE 15+标志下可用


Webkit-实现,默认情况下在Safari 10.1中启用


Node.js-正在审议中,需要进一步讨论

获取环境来测试

正如我们看到的,目前您可以在Safari 10.1+和EDGE 15 Preview Build中测试本机JS模块。让我们下载并启用其中的功能:


在Firefox中使用ES模块

目前你必须下载Firefox Nightly,这意味着它很快就会到来FF Developer Edition并且会接着在稳定版本中实现。


启用ES模块:

打开about:config页面
点击“我接受风险!”
搜索dom.moduleScripts.enabled启用标志
双击并且将它的值转化为"true"

就这样,现在你可以测试模块脚本如何在FF中工作。


在启用ES模块的情况下获取Safari技术预览

如果您使用macOS,只需从developer.apple.com下载最新的Safari技术预览(TP)安装并打开它。


从Safari 技术预览版本21+开始,并且会默认启用ES模块。


如果是Safari TP 19或20,请检查ES6模块功能是否已启用,打开“开发”菜单 - >“实验功能” - >“ES6模块”。


原生ECMAScript模块(ECMAScript modules)概述-


另一个选项是下载最新的Webkit Nightly并使用它。


启用ES模块的EDGE 15

你可以从Microsoft下载免费的虚拟机。


只需选择虚拟机(VM)“Win 10预览版(15.XXXXX)上的Microsoft EDGE”以及例如 “虚拟盒”(也免费)作为平台。


安装并运行VM,并打开EDGE浏览器。


打开about:flags页面,然后选中“启用实验性JavaScript功能”复选框


原生ECMAScript模块(ECMAScript modules)概述-


就这样,现在你有2个环境,你可以使用ECMAScript模块的本地实现


原生和捆绑模块的区别

让我们从本地模块功能开始:


1. 每个模块都有自己的作用域,而不是全局作用域 2. 它们总是处于严格模式,即使没有提供“use strict”指令 3. 模块可以使用import指令导入其他模块 4. 模块可以使用导出来导出绑定


到目前为止,我们没有面对与我们习惯于使用打包的巨大差异。


最大的区别在于为浏览器提供入口点的方式。您必须提供具有特定属性type =“module”的script标签,例如:



1



这告诉浏览器你的脚本可能包含其他脚本的导入,他们应该被相应地处理。


这里出现的主要的问题是:



为什么JavaScript解释器无法自行检测文件是否是模块?



这里是其中一个原因


模块默认处于严格模式,经典的 scripts- no:


1. 让我们说解释器解析文件,假设它是一个不是严格模式的经典脚本


2. 然后找到“import / export”指令


3. 在这种情况下,它应该从头开始在严格模式下再次解析所有代码


另一个原因 - 相同的文件可以没有严格模式的有效,并与它无效。然后有效性取决于它被解释的方式,这导致意想不到的问题。


定义期望的文件加载的类型为许多优化方法创造了条件。例如,在解析文件的其余部分之前并行加载文件导入)。你可以找到一些使用Microsoft Chakra JavaScript引擎对于ES模块的示例。


Node.js将文件标记为模块的方式

Node.js的性质不同于浏览器和使用``的解决方案也不适用。


目前,[合适的解决方案仍在讨论}(https://github.com/nodejs/node/wiki/ES6-Module-Detection-in-Node)。


有一些解决方案被社区否决了:


1. 在每一个文件添加"use module";


2. Meta在package.json中


其他选项仍在考虑中(感谢@bmeck的突出贡献):


1.决定源代码是否是ES 模块


2. 在ES6模块中使用新的文件拓展名.mjs,如果之前的版本没有办法工作工作的话,这个选择可以作为备选。



1
每个方法都各有利弊,目前,[Node.js如何发展还是未知的](https://github.com/nodejs/node-eps/blob/master/002-es6-modules.md))。


简单原生模块例子

好的,首先让我们先创建一个简单的演示(您可以在您设置的环境中运行来进行测试。因此,它将是一个简单的模块,它会引入另外一个模块并且调用其中的一个方法。第一步-使用``来包括这个文件:



1


2
3
4
5


6
7
8

模块文件



1
// main.js

2
import utils from "./utils.js";

3
4
utils.alert(

5
JavaScript modules work in this browser:

6
https://blog.whatwg.org/js-modules

7
);


最后,引入的utils:



1
// utils.js

2
export default {

3
alert: (msg)=>{

4
alert(msg);

5
}

6
};


您可能会注意到,当使用import指令的时候,我们会提供.js文件拓展名。这是和通常的打包行为的另外一个区别-原生模块不会默认添加.js拓展名。


实际上,这意味着你必须提供确切的URL。主要的要求是资源应该有一个正确的MIME类型(感谢@bradleymeck纠正这个)


第二,让我们来检查模块的作用域(演示):



1
var x = 1;

2
3
alert(x === window.x);//false

4
alert(this === undefined);// true


第三-我们会检查原生模块是在严格模式下。例如,严格模式禁止删除纯名称。因此下面的演示会显示出在模块脚本中抛出错误:



01
// module.js

02
var x;

03
delete x; // !!! syntax error

04
05
alert(

06
THIS ALERT SHOULDN'T be executed,

07
the error is expected

08
as the module's scripts are in the strict mode by default

09
);

10
11
// classic.js

12
var x;

13
delete x; // !!! syntax error

14
15
alert(

16
THIS ALERT SHOULD be executed,

17
as you can delete variables outside of the strict mode

18
);


严格模式在模块脚本中是不可避免的。


注意

.js拓展名不能被省略(应该提供确切的 URL)


作用域不是全局的,this不指向任何变量


原生模块默认处于严格模式下 (不再需要提供‘use strict’ )

内联模块脚本

和经典的脚本一样,你可以内敛代码,而不是在单独的文件中提供它。在之前的演示中,你可以将main.js直接在放在 ``之中,这会导致相同的行为:



1



注意

以执行脚本或加载外部文件并作为模块使用执行它 浏览器如何加载并且执行模块

模块都是默认延迟加载的。为了理解这一点,你可以想象它们都具有一个默认的defer属性。


下面是规范中解释这一行为的图片:


原生ECMAScript模块(ECMAScript modules)概述-


这意味着,默认模块脚本不阻塞,并行加载,并在页面完成解析时执行。


因此您可以通过添加async属性来改变这种行为,因此这个脚本只会在加载的时候执行。


默认行为和经典主要的区别是:经典脚本会被立即读取和计算,直到这两步完成才会开始解析。


为了表示它,下面是一个带有脚本选项的演示,在这第一个将是一个没有defer/async属性的经典脚本:



1


2


3


4


5



其它顺序取决于浏览器的实现,脚本的大小,导入脚本的数量等。


写在最后:FOR Freedom 看看外边的世界,以及IT这一行,少不了去Google查资料,最后,安利一个国外网络加速器。一枝红杏加速器,去Google查资料是绝对首选,连接速度快,使用也方便。我买的是99¥一年的,通过这个链接(http://my.yizhihongxing.com/aff.php?aff=2509)注册后输上会员中心得优惠码,平摊下来,每月才7块钱,特实惠。


本文标签: JavaScript ECMAScript模块 ES6模块 CommonJS Safari技术 服务器



转自 SUN'S BLOG - 专注互联网知识,分享互联网精神!


原文地址: 《原生ECMAScript模块(ECMAScript modules)概述》


相关阅读:《Aaron Swartz – 互联网天才开挂的人生历程:每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的?》相关阅读:《网站环境apache + php + mysql 的XAMPP,如何实现一个服务器上配置多个网站?》


相关阅读:《什么是工程师文化?各位工程师是为什么活的?作为一个IT或互联网公司为什么要工程师文化?》


相关阅读: 对程序员有用:2017最新能上Google的hosts文件下载及总结网友遇到的各种hosts问题解决方法及配置详解


相关阅读: 《win10永久激活教程以及如何查看windows系统是不是永久激活?》


相关BLOG:SUN’S BLOG- 专注互联网知识,分享互联网精神!去看看:www.whosmall.com



原文地址:http://whosmall.com/?post=237

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索模块 , ecmascript , 原生 , 概述 Modules ,以便于您获取更多的相关知识。