# Module

ES6 模块的设计思想，是尽量的静态化，使得编译时就能确定模块的依赖关系，以及输入和输出的变量。 ES6 模块不是对象，而是通过`export`命令显式指定输出的代码，再通过`import`命令输入。

## 严格模式

ES6模块默认使用严格模式，不管是否有`use strict`。

严格模式特点：

* 变量必须声明后再使用
* 函数的参数不能有同名属性，否则报错
* 不能使用`with`语句
* 不能对只读属性赋值，否则报错
* 不能使用前缀0表示八进制数，否则报错
* 不能删除不可删除的属性，否则报错
* 不能删除变量`delete prop`，会报错，只能删除属性`delete global[prop]`
* `eval`不会在它的外层作用域引入变量
* `eval`和`arguments`不能被重新赋值
* arguments不会自动反映函数参数的变化
* 不能使用`arguments.callee`
* 不能使用`arguments.caller`
* 禁止this指向全局对象，实际会指向`undefined`
* 不能使用`fn.caller`和`fn.arguments`获取函数调用的堆栈
* 增加了保留字（比如`protected`、`static`和`interface`）

## export 命令

```javascript
export var firstName = 'Michael';

var year = 1958;
export {year};
```

`export`命令不可以在块级作用域内使用。

`export`命令规定的是对外的接口，必须与模块内部的变量建立一一对应关系。 不可以直接输出值。

```javascript
// 报错
export 1;

// 报错
var m = 1;
export m;
```

`export`的接口与对应的值是动态绑定的，取到的是模块内部实时的值。

```javascript
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
```

## import 命令

使用`import`模块加载`export`定义的对外接口。

`import`导入模块与`export`对外接口的名称必须相同。

```javascript
// main.js
import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}
```

`import`的特点：

1. `import`命令有提升效果，提升到头部首先执行。
2. `import`是静态执行，不能使用表达式或者变量。
3. `import`同一个模块加载多次，也只会执行一次。

整体加载：

```javascript
import * as circle from './circle';

console.log('圆面积：' + circle.area(4));
console.log('圆周长：' + circle.circumference(14));
```

会一起加载模块当中的两个方法。

## 默认模块加载

```javascript
// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入
```

一个模块只能有一个默认输出,`export default`命令只能使用一次。 `export default`本质是将该命令后面的值，赋给`default`变量。

> 参考： <http://es6.ruanyifeng.com/#docs/module>

## 使用备注

`import`与`export`命令在Nodejs环境中不支持，建议使用`traceur`运行ES6代码文件。

安装：

```bash
#本地安装，
npm install traceur -D
#然后调用二进制文件
node_modules/.bin/traceur a.js


# 也可以全局安装
npm install traceur -g
# 调用命令

traceur a.js
```

## 脚本异步加载

`script`标签如果有`defer`或`async`属性，脚本就会异步加载。

区别：

* defer：整个页面正常渲染结束，才会执行
* async：一旦下载完，渲染引擎就会中断渲染，执行这个脚本以后，再继续渲染。

多个`defer`脚本会按顺序加载，`async`不能包证按顺序加载。

## ES6 模块与 CommonJS 模块的差异

区别：

* CommonJS 模块输出的是一个值的拷贝，ES6 模块输出的是值的引用。
* CommonJS 模块是运行时加载，ES6 模块是编译时输出接口。

ES6`import`的模块原始值变了，import加载的值也会跟着变。

```javascript
// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}

// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
```

模块变量是一个“符号链接”，只读，赋值会报错。

```javascript
// lib.js
export let obj = {};

// main.js
import { obj } from './lib';

obj.prop = 123; // OK
obj = {}; // TypeError
```

CommonJS模块如果是原始类型的值，不会影响输出值，但可以写成函数，会等到变动后的结果。

```javascript
// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  get counter() {
    return counter
  },
  incCounter: incCounter,
};

// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 4
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://note.niefee.com/directory-2/module.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
