//此时的导入语法
import obj from './a.js'
obj.a(); //aaa
console.log(obj.c) //ccc
//注意,此时不能用大括号导入,下面会报错
import {a, b, c} from './a.js' //报错
2.5、export 的错误语法
export
命令不能直接输出变量,因为变量的值必须在运行阶段才能确定,而 export 命令的输出是在编译阶段就已经输出。
// 报错
export 1;
// 报错
var m = 1;
export m;
// 报错
function f() {}
export f;
export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
如何理解这句话?(可以参考:https://www.imooc.com/wenda/detail/458477)
export 1 ,这里输出的是一个值 1,没有与任何模块内部变量建立联系,所以直接报错。
var m = 1; export m; 这里看起来就像是输出了一个变量m作为对外的接口,我们可能会认为 m 这个变量被输出到模块外被使用,并且与模块内的 m 产生了引用的关系。然而现实情况是,变量m在模块中作为一个变量存在,但是通过export导出m时,被导出的只有m的值 1,所以同样不与内部变量产生联系,于是报错。
这跟函数的传参是一个道理:
let x = 1; //声明变量
const foo=(x)=>{x=2}; //声明一个函数
foo(x) //传入x
console.log(x) // 1
上面代码中,变量 x 作为 foo 的参数,只把变量 x 的值传入 foo,x 只作为数值的载体,函数内部 x 并没有与变量 x 产生直接联系。只是复制了变量 x 的值(这种复制值然后再使用的形式与CommonJS加载模式类似)。
2.5.1、export default 的错误语法
export default
命令其实只是输出一个叫做default
的变量,所以它后面不能跟变量声明语句。
// 错误
export default var a = 1;
同样地,因为export default
命令的本质是将后面的值,赋给default
变量,所以可以直接将一个值写在export default
之后。
// 正确
export default 42;
// 报错
export 42;
2.6、export 中 default 和其他输出结合使用
export 中 default 是可以和其他输出结合使用的
// a.js 输出 下面将输出三个函数
export default function (obj) {
export function each(obj, iterator, context) {
export { each as forEach };
// b.js 输入 这里可以分别输入三个值
import aaa, { each, forEach } from 'a.js';
3、import 命令
使用export
命令定义了模块的对外接口以后,其他 JS 文件就可以通过import
命令加载这个模块。
import
命令输入的变量都是只读的,不可以在加载后修改引入的变量。但如果引入的变量是对象的话,可以修改对象的属性,但非常不推荐使用。
import {obj} from './a.js'
obj = {}; // Syntax Error : 'obj' is read-only;
上面代码中,对引入变量重新赋值就会报错。但是,如果a
是一个对象,改写a
的属性是允许的,但非常不推荐修改引入的变量,因为其他引入的模块也可以读到改写后的值,这种写法很难查错,所以凡是输入的变量,都当作完全只读,轻易不要改变它的属性。
import
命令具有提升效果,会提升到整个模块的头部,首先执行,因为 import 命令是编译阶段执行的,在代码运行之前。
foo();
import { foo } from 'my_module'; //这里不会报错,因为import的执行早于foo的调用
import
语句会执行所加载的模块,因此可以有下面的写法。如果多次重复执行同一句import
语句,那么只会执行一次模块的文件代码,而不会执行多次。也就是说import
语句是 Singleton 模式。
import 'a.js'; //这里仅仅执行lodash模块,但是不输入任何值,所以并不能使用 a.js 里面定义的变量
//下面代码加载了两次lodash,但是只会执行一次。
import 'lodash';
import 'lodash';
import { foo } from 'my_module';
import { bar } from 'my_module';
// 等同于
import { foo, bar } from 'my_module';
目前阶段,通过 Babel 转码,require
命令和import
命令可以写在同一个模块里面,但是最好不要这样做。因为import
在静态解析阶段执行,所以它是一个模块之中最早执行的。
//下面的代码可能不会得到预期结果,因为import将会于require之前执行
require('core-js/modules/es6.symbol');
require('core-js/modules/es6.promise');
import React from 'React';
import 的语法有多种,下面将逐一介绍:
3.1、import {} from 'xxx.js'
// a.js 输出
var firstName = 'Michael';
var lastName = 'Jackson';
export { firstName, lastName};
// b.js 输入
import { firstName, lastName} from './a.js';
//引入后可以直接使用
console.log(firstName,lastName)
3.2、import {a as newName} from 'xxx.js'
如果想为输入的变量重新取一个名字可以使用as
关键字,将输入的变量重命名。as 关键字后面的是输入的变量名,即你想使用的名字
import { firstName as newName } from './a.js';
3.3、import * as newName from 'xxx.js'(模块的整体加载)
除了指定加载某个输出值,还可以使用整体加载,即加载模块的整个输出对象。用星号(*
)指定一个对象,所有输出值都将加载在这个对象上面。
// a.js
export var area = 'aaa'
export function circumference(radius) {
return 2 * Math.PI * radius;
//b.js
import * as newObj from './circle';
console.log(newObj .area);
console.log(newObj .circumference(14));
不允许修改整体加载的对象
import * as circle from './circle';
// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};
3.4、import 的错误语法
import不
能使用表达式和变量,因为 import 是静态执行的,即编译阶段执行,而这些语法只有在运行时才能得到结果。
// 报错
import { 'f' + 'oo' } from 'my_module';
// 报错
let module = 'my_module';
import { foo } from module;
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
4、export 和 import 的复合写法
如果在一个模块之中,先输入后输出同一个模块,import
语句可以与export
语句写在一起。
export { foo, bar } from 'my_module';
// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };
但需要注意的是,写成一行以后,foo
和bar
实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo
和bar
。
其他的复合写法:
// 接口改名输出
export { foo as myFoo } from 'my_module';
//等同于
import {foo} from 'mu_module'
export {foo as myFoo}
// 整体输出
export * from 'my_module';
//默认接口的写法
export { default } from 'foo';
//具名接口改为默认接口的写法
export { es6 as default } from './someModule';
// 等同于
import { es6 } from './someModule';
export default es6;
//默认接口改名为具名接口
export { default as es6 } from './someModule';