# Module

# 概述

ES6 之前,有CommonJS和AMD模块规范,CommonJS 和 AMD 模块,都只能在运行时确定这些东西,ES6 可以在编译时就完成模块加载

// CommonJS模块
let { stat, exists, readFile } = require('fs');
// ES6模块
import { stat, exists, readFile } from 'fs';

# 严格模式

ES6 的模块自动采用严格模式
严格模式主要有以下限制:

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

# export

模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

//变量
let name='michael'
export {name}
export const year = 1958;
//function
export function add(x, y) {
  return x + y;
};
// 正确
function f() {}
export {f};
export default functon bar(){} //默认模块,import 不用加花括号
//一个模块只能有一个默认输出,因此export default命令只能使用一次。
//export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字
// 正确
export let a = 1;

// 正确
let a = 1;
export default a;

// 错误
export default let a = 1;

# import

import命令具有提升效果,会提升到整个模块的头部,首先执行,本质是import命令是编译阶段执行的,在代码运行之前。

// main.js
import {firstName, lastName} from './profile.js';
import { lastName as surname } from './profile.js';//重命名为surname
//整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。
import * as circle from './circle';
//应该是可以静态分析的,所以不允许运行时改变

# 加载实现

<script>标签打开defer或async属性,脚本就会异步加载
defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

<script src="./foo.js" defer></script>
<script src="./foo.js" async></script>
//加载es6模块 异步加载,不会造成堵塞浏览器 等同于打开了<script>标签的defer属性。
<script type="module" src="./foo.js"></script>
//内嵌在网页
<script type="module">
  import utils from "./utils.js";

  // other code
</script>

# ES6 模块与 CommonJS 模块

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

# 相等运算符

相等运算符(==)是一个很让人头痛的运算符

x == y
0 == null // false
  • 如果x不是正常值(比如抛出一个错误),中断执行。
  • 如果y不是正常值,中断执行。
  • 如果Type(x)与Type(y)相同,执行严格相等运算x === y。
  • 如果x是null,y是undefined,返回true。
  • 如果x是undefined,y是null,返回true。
  • 如果Type(x)是数值,Type(y)是字符串,返回x == ToNumber(y)的结果。
  • 如果Type(x)是字符串,Type(y)是数值,返回ToNumber(x) == y的结果。
  • 如果Type(x)是布尔值,返回ToNumber(x) == y的结果。
  • 如果Type(y)是布尔值,返回x == ToNumber(y)的结果。
  • 如果Type(x)是字符串或数值或Symbol值,Type(y)是对象,返回x == ToPrimitive(y)的结果。
  • 如果Type(x)是对象,Type(y)是字符串或数值或Symbol值,返回ToPrimitive(x) == y的结果。
  • 返回false。