[ ES2015 ] JavaScript 中的 export 关键字

yufei       5 年, 8 月 前       1928

ECMAScript®2015 语言规范中添加了模块化的功能。而 JavaScript 模块化最依赖的两个语法就是 export 关键字和 import 关键字

  • 前者用于导出一个模块中声明的提供给其它模块使用的东西
  • 后者则用于将一个模块中使用 export 导出的东西导入到当前所在的脚本中

本章节,我们就来讲讲前者,也就是 export 关键字

export 关键字说明

MDN 上对 export 的描述是

export 语句用于在创建 JavaScript 模块时,从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们

理解这句话就要弄懂两个地方,一个是什么是 JavaScript 模块,另一个是可以导出的东西到底有那些 ?

JavaScript 模块

对于什么是 JavaScript 模块 ? 我想,这应该不是一个问题,但是,它其实又是一个问题

JavaScript 模块,通俗的江,就是一个独立的 JavaScript 文件,模块中可以包含一些变量,一些常量,一些类,一些函数,甚至是任何可以执行的代码。

模块 vs 普通脚本文件

创建模块时,一个 JavaScript 模块,跟我们平时写的 JavaScript 文件没什么差别

那么 JavaScript 模块和我们平时编写的普通的 JavaScript 文件有啥区别呢 ?

区别就在于运行时的代理 ( 浏览器或 Node.js ) 是如何对待两者的

  • 对于普通文件,准确的说,是浏览器中的普通脚本文件 ( 因为 Node.js 下不存在普通文件 ),所有的文件级别的声明都是默认全局的,也就是都在 window 这个超级变量上

  • 而对于模块,例如 Node.js 中的文件,或者浏览器上声明为 text/module 的文件,文件级别的声明默认是私有的,除非特别说明 ( 使用 export 导出 ),否则外部的其它文件是无法访问的

如果要细细说明,那么就会涉及到 exportimport 两个关键字语法,就会产生鸡和蛋的问题。

所以,我们这里,对模块只有一个定义,就是一个 JavaScript 文件

export 语法

ECMAScript®2015 对 export 的语法做了如下定义

export { name1, name2, , nameN };
export let name1, name2, , nameN; // also var
export let name1 = , name2 = , , nameN; // also var, const
export function FunctionName() {...}
export class ClassName {...}

export default expression;
export default function () {  } // also class, function*
export default function name1() {  } // also class, function*

export { name1, name2, , nameN } from ;


export * from ;

export { name1 as default,  };
export { variable1 as name1, variable2 as name2, , nameN };
export { import1 as name1, import2 as name2, , nameN } from ;

参数 nameN 表示要导出的标识符(用来被其他脚本的 import 导入 )

当看到这些语法时是不是吓了一大跳,这么复杂...其实,你只要阅读了我的说明,就不会觉得复杂了

你也看到了,我其实是故意将这些语法分为 5 组的,每各分组代表了一种用途

  1. 第一组:导出一个模块中声明的东西

    大家先想想,对于一个网页中的普通的文件,我们在文件中定义或声明的什么东西才会添加到 window 超全局变量上 ?

    想想 ?

    1. 使用 var 声明的变量
    2. 使用 let 声明的不可变变量
    3. 使用 const 声明的常量
    4. 使用 function 声明的函数
    5. 使用 function* 声明的生成器函数 6.. 使用 class 声明的类

    所以,对于一个 JavaScript 文件,所有能被添加到 window 超全局变量上的东西,都能被导出

    而第一个 export { name1, name2, …, nameN }; 与后面几个的差别,就相当于是前者先声明这些东西,然后再导出

    js var name1; const name2; let name3; export name1, name2, …, nameN;

    后者将声明和导出放到一起

  2. 第二组:第二组与第一组的差别,就在于 default 关键字和 export default expression

    1. default 是默认的意思,export default 的意思就是默认导出,也称之为匿名导出,说默认导出你可能不太理解,说匿名导出你应该就理解了,因为 JavaScript 有匿名函数的存在

      hello.js

      var hello = function(){}
      export default hello;
      

    当使用 export default hello 的时候,对于导入语法 import func from hellofunc 其实就是 hello

    所以,JavaScript 模块有一条规则,那就是 只能有一个 export default

    JavaScript 模块还有另一个规则,就是 **不能使用 varletconst 作为默认导出

    1. 理解了 export default 那么对于 export default expression 应该就很好理解了,就是先求取 expression 表达式的值,然后再 export default
  3. export ... from ... 对于前面的两组,都是导出 export 关键字所在的模块中的声明,但 export ... from ... 则可以导出另一个模块中声明的东西

    这个语法很有意思,有了这种语法,我们就可以创建子模块功能,然后在同一入口中导出所有公开的声明

    假设我们有一个模块 greeting ,目录结构如下

    .
    |-- index.js
    |--- hello.js
    

    假设 hello.js 中的代码如下

    export function hello() { return 'Hello World'; }
    

    那么 index.js 中就可以使用

    export hello from hello
    

    对于其它需要使用 greeting 模块的项目,只要使用下面的语句就可以使用 hello 函数

    import hello from index
    
  4. export * from …;,当你看懂了第三组语法,那么第四种语法就很简单了,就是一种偷懒的写法,就是把 ... 文件中导出的声明再次导出,本质上来说,就是 export name1,name2,name3,... from ... 的简写

    需要注意的是: export * from ... 不会导出已导入模块中的默认导出,如果要导出已导入模块中的默认导出,需要使用下面的语句

    import mod from "mod";
    export default mod;
    
  5. export as 语法,我们也称之为别名导出,原来 export name1 的时候导出的名字是 name1 ,那么使用 export name1 as alias1 的时候,就是给 name1 取一个别名 alias1 然后再导出这个别名

这 5 组导出方式,我们可以根据有无 default 关键字分类,命名导出默认导出 ,这种划分的原因一方面是因为有无 default 关键字,另一方原因是 import 也会区别对待它们

  • 命名导出对导出多个值很有用。在使用 import 导入期间,必须使用相应对象的相同名称

  • 可以使用任何名称导入默认导出,唯一的规则就是 只能有一个默认的导出 ,例如

    假设同一个目录下存在两个文件 test.jsmain.js

    test.js 中的内容如下

    export default k = 12; // in file test.js
    

    main.js 中的内容如下

    import m from './test' // 我们可以自由使用任意标志符来替换 k,比如 m,因为 k 是默认导出的
    console.log(m);        // will log 12
    

范例

  1. 使用命名导出

    假设在某个模块 mymodule.js 中有如下代码

    mymodule.js

    function cube(x) {
        return x * x * x;
    }
    
    const foo = Math.PI + Math.SQRT2;
    
    export { cube,foo };
    

    那么再其它脚本中,我们可以这样使用

    import { cube, foo } from 'mymodule.js';
    console.log(cube(3)); // 27
    console.log(foo);    // 4.555806215962888
    
  2. 默认导出

    如果我们要导出一个值或模块中的返回值,就可以使用默认导出

    mymodule.js

    export default function cube(x) {
        return x * x * x;
    }
    

    然后,在另一个脚本中,可以直接导入默认导出:

    import cube from 'mymodule';
    console.log(cube(3)); // 27
    

浏览器兼容性

虽然 exportES2015 标准规范中的东西,但很遗憾,戒指目前,在很多浏览器中仍然不被支持

此特性目前仅在 SafariChrome 原生实现,当然也为此除了很多转换器,比如 Traceur CompilerBabelRollup

其中以 Babel 最为出名

至于具体的浏览器兼容性,可以查看下表

PC 浏览器

至于浏览器兼容性问题,可以访问

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/export

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.