import
命令用于输入其他模块提供的功能。
ECMAScript 规范中的模块化方案提供了四种引入模块的方式:
从源模块导入其原始名称的特定项目。
import { originModule } from './module.js'// React Hookimport { useState, useEffect } from 'react'
从源模块导入特定项,并在导入时指定自定义名称。使用关键字 as
,将输入的变量重命名。
import { originMoudle as newMoudleName } from './module.js'
将源模块中的所有内容作为对象导入,将所有源模块的命名导出公开为属性和方法。默认导出被排除在此对象之外。
import * as module from './module.js'// Node.js `fs` moduleimport * as fs from 'fs'
上述例子中 originModule
将被附加到作为属性的导入对象上,即 module.originModule
。
导入源文件的默认导出。
import module from './module.js'
加载模块代码,但不要创建任何新对象。
import './module.js'
import
命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
import { foo } from './module.js'foo = { a: 1 }// Syntax Error : 'a' is read-only;
但是,如果输入变量是对象类型,改写该变量是被允许的。
import { bar } from './module.js'bar.a = 1// Right
尽管此处修改的对象属性,在其他模块也可以读取改写后的值。不过,这种做法很难查错,因此建议凡是输入的变量,都当作只读变量,轻易不要修改它。
import
后面的 from
指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js
后缀可以省略。
如果只是模块名,不带有路径,那么必须有配置文件(通常从引入模块目录下 package.json
中查找),告诉 JavaScript 引擎该模块的位置。
import React from 'react'
注意,import
命令具有提升效果,import
命令无论写在文件中的哪一行,都会提升到整个模块的头部,首先执行。
foo()import { foo } from './module.js'
上面的代码不会报错,因为 import
的执行早于 foo
的调用。这种行为的本质是,import
命令是编译阶段执行的,在代码运行之前。
由于 import
是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 报错 - 使用了表达式import { 'f' + 'oo' } from 'my_module';// 报错 - 使用了变量var module = 'my_module';import { foo } from module;// 报错 - 使用了判断语句if (x === 1) {import { foo } from 'module1';} else {import { foo } from 'module2';}
上面三种写法都会报错,因为它们用到了表达式、变量和 if
结构。在静态分析阶段,这些语法都是没法得到值的。
如果多次重复执行同一句 import
语句,那么只会执行一次,而不会执行多次。
import 'lodash'import 'lodash'
上面代码加载了两次 lodash
,但是只会执行一次。
import { foo } from 'my_module';import { bar } from 'my_module';// 等同于import { foo, bar } from 'my_module';
上面代码中,虽然 foo
和 bar
在两个语句中加载,但是它们对应的是同一个 my_module
实例。也就是说,import
语句是 Singleton 模式。
目前阶段,通过 Babel 转码,CommonJS 模块的 require
命令和 ES6 模块的 import
命令,可以写在同一个模块里面,但是最好不要这样做。因为 import
在静态解析阶段执行,所以它是一个模块之中最早执行的。下面的代码可能不会得到预期结果。
require('core-js/modules/es6.symbol')require('core-js/modules/es6.promise')import React from 'React'