资讯专栏INFORMATION COLUMN

ES6: import和export

wapeyang / 3281人阅读

摘要:一模块化前端模块化的好处都已经被说烂了,归纳为两点避免全局变量污染有效的处理依赖关系终于引入了模块的概念,最近学习了下,顺便记下笔记。命名导出命名导出就是明确导出的变量名称和值。其中表示导出模块所有的命名输出。

一、模块化

前端模块化的好处都已经被说烂了,归纳为两点:

避免全局变量污染

有效的处理依赖关系

ES2015终于引入了模块的概念,最近学习了下,顺便记下笔记。

二、准备工作

借助Babel演示Demo。
创建个module目录,并在该目录里执行:

npm init -y

然后安装各种依赖:

npm install --save-dev babel-cli babel-preset-env babel-preset-es2015

接着创建.babelrc文件:

{
  "presets": [
      "es2015",
      "env"
      ]
}

修改package.json文件的"scripts"配置:

"scripts": {
    "build": "babel src --out-dir dist"
  }

最终的目录结构如:

三、模块导出

一个文件定义一个模块;

通过export语句导出该模块输出的变量。export语句有两种语法格式:命名导出默认导出

1.命名导出

命名导出就是明确导出的变量名称和值。
在src目录下创建math.js,index.js文件。
math.js内容:

// Case 1: export后面跟变量输出声明语句
export var PI = 3.14;

// Case 2: export后面直接跟变量定义语句
export var add = function (x, y) { // 导出函数print
    return x + y;
}

这表示math.js模块导出变量PI和add, 用NodeJS的模块格式可表示为:

var PI = 3.14;
var add = function (x, y) { // 导出函数print
    return x + y;
}

module.exports.PI = PI; 
module.exports.add = add;

index.js内容:

import * as Math from "./math.js"; // import是导入模块,后面会说。

console.log(Math.PI);
console.log(Math.add(1, 2));

然后执行下面的命令进行Babel转换:

npm run build

如果没有报错的化,那module目录下应该生成了dist子目录,并且生成了index.js和math.js文件(先不要在意文件的内容)。
然后在执行命令:

node dist/index.js

看看输出结果是否OK:

3.14
3

如果导出多个变量,可以采用简写格式(调整math.js内容):

var PI = 3.14;
var add = function (x, y) { 
    return x + y;
}
export { PI, add }; // 简写格式,统一列出需要输出的变量

重复上述步骤中执行npm和Node命令查看看输出结果是否OK。
并且该简写格式还可以对输出的变量重命名,之前的都是模块里声明的变量名作为模块导出的变量的名
再次修改math.js

var PI = 3.14;

var add = function (x, y) { 
    return x + y;
}

export { PI, add as Add}; // 把输出变量add重命名为Add(注意不用双引号)

通过关键字as把输出变量add重命名为Add,注意Add是个字面量,不是字符串不需要引号。同样在导入math.js模块的index.js模块也要修改下:

import * as Math from "./math.js";

console.log(Math.PI);
console.log(Math.Add(1, 2)); // Add方法名称改动了。

命名导出需要同时制定导出的变量名称和变量值,所以export语句后面跟的一般是变量输出声明语句块变量定义语句,不可以是表达式,因为表达式只有值,没有名字。

2. 默认导出

通过关键字default修饰export可以指定一个模块的默认输出变量值(在导入模块的默认输出时,不需要指定导出变量名称,这个后面再说)。

// Case 3 常量
export default 25; 

// Case 4 变量
var PI = 3.14;
export default PI 

// Case 5 函数
export default function add2( x, y) {
    return x + y;
}

注意

一个模块最多只能有一个默认导出;

默认输出可以视为名字是"default"的模块输出变量;

默认导出后面可以是表达式,因为它只需要值;

export语句必须在模块作用域的最顶层,即export不可以出现在任意花括号内,如函数语句里,子代码块里(控制语句)。

四、模块导入

通过import语句导入外部模块。对应export语句的两种导出方式(命名模块导出和默认模块导出),import也分别存在两种不同的模块导入语法格式。

1. 导入模块的命名输出变量

修改index.js:

import { PI, Add} from "./math.js";
console.log(PI);
console.log(Add(1, 2));

表示:导入math.js模块里输出的变量PI, Add,注意名称必须要和math.js模块的输出变量一一对应,否则就是undefined。
重新执行npm和node命令看看输出是否OK。
该格式还支持对导入的变量重命名:

import { PI as pi, Add as add} from "./math.js";

如果导入一个模块所有命名输出,可采用通配符"*:
修改index.js:

import * as Math from "./math.js"; // 此时必须通过as指定个别名
console.log(Math.PI);
console.log(Math.Add(1, 2));

表示导入模块math.js所有命名输出变量,并通过Math变量引用。

2. 导入模块的默认输出

修改math.js:

var PI = 3.14;

var add = function (x, y) { 
    return x + y;
}

export { PI, add as Add}; // 简写格式,统一列出需要输出的变量

export default function say() { // 默认输出
    console.log("I am default export");
}

修改index.js:

import say  from "./math.js"; // 
say();

表示导入模块math.js的默认输出,此时不可以用as重命名哦(因为名字可以任意定义)。

执行命令查看输出是否OK。

导入模块默认输出的名字可以任意命名。

import say2  from "./math.js"; // 
say2();

如果同时导入模块的命名输出和默认输出,可采用格式:

import say, * as Math from "./math.js"; 
// OR
import say, { PI, Add } from "./math.js"; 

有个限制条件默认导入一定放在命名导入前面,即不能写成:

import * as Math, say from "./math.js"; 
// OR
import { PI, Add }, say from "./math.js"; 

同样import语句也必须在模块的最顶层作用域里,即import不可以出现在任意花括号内,如函数语句里,子代码块里(控制语句)。

3. 只导入

如果只导入一个模块,但不引用模块的输出变量,可以简写为:

import "./math.js"

此时只会出发模块math.js的执行。

五、修改导入/导出的变量值 1. 修改导入的变量值

模块可以导出任何类型变量(引用变量和值变量),如果在模块index.js里修改了模块math.js导出的引用变量或者值变量,那会影响模块math.js里的值么?
修改math.js:

var PI = 3.14;
var Person = {
    name: "Bob"
}

export { PI, Person}; 
export default function say() {
    console.log(`Person:${JSON.stringify(Person)}, PI:${PI}`)
}

修改index.js:

import say, * as Math from "./math.js"; 

say(); // 修改前
Math.Person = 12;
Math.PI = 0;
say(); // 修改后

执行npm和node查看输出:

从输出可以看出虽然我们在index.js模块里修改了math.js模块的导出变量,但并不会影响math.js里的值。

2. 修改导出的变量值

反过来想想,如果模块math.js修改了其导出的引用变量或者值变量在,那会影响模块index.js里的取值么?
修改math.js:

var Count = 0;
var increase =  function() {
    Count++;
}
var Person = {
    name: "Bob"
}
var changeName = function() {
    Person.name = "John";
}

export { Count, Person, increase, changeName}; 

修改index.js:

import say, * as Math from "./math.js"; 

console.log(`Person:${JSON.stringify(Math.Person)}, Count:${Math.Count}`);// 修改前
Math.increase();
Math.changeName();
console.log(`Person:${JSON.stringify(Math.Person)}, Count:${Math.Count}`);//  修改后

输出:

从输出可以看出只要math.js修改了导出值就会影响index.js的取值。

3. 小结

模块的输出变量(引用类型或者值类型)对其他引用模块来说都是只读的

模块修改了其输出变量的值会影响其他引入模块的取值。

六、再看export语句

了解了export和import的用法后,我们再看看export语句另一个语法规则:导出引入的模块的变量。上面的例子里export语句都是导出模块自身定义的变量,export还可以导模块引入模块的输出。
在src目录添加文件log.js:

export var Log = function(msg) {
    console.log(msg);
}
export default "I am log.js";

修改math.js:

var Count = 0;
var increase =  function() {
    Count++;
}
var Person = {
    name: "Bob"
}

var changeName = function() {
    Person.name = "John";
}

export { Count, Person, increase, changeName}; 
export default function say() {
    console.log(`Person:${JSON.stringify(Person)}, Count:${Count}`)
}
export * from "./log.js"; // 

修改index.js:

import say, * as Math from "./math.js"; 

Math.Log("hello"); // 该方法来之log.js模块

查看下输出是否OK。

其中“export * from "./log.js";”表示导出模块log.js所有的命名输出。等价于:

export { Log } from "./log.js";

注意:这种语法格式“export * from "./log.js";”不可以定义别名,而花括号的语法格式“export { Log } from "./log.js"”可以定义别名,即:

export { Log as log} from "./log.js"

怎么在math.js模块里导出模块log.js的默认输出呢?只能采用先导入,再导出方式:

import logName from "./log.js";
export { logName }
参考

MDN export

MDN import

Babel 入门教程

Babel Learn ES2015

An Introduction To JavaScript ES6 Modules

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90086.html

相关文章

  • [译]ES6 模块化入门

    摘要:当我们学习的模块化,就会发现它的发展深受的影响。严格模式在模块系统中,严格模式是默认开启的。同样的,模块内部的声明只在模块内部有效。在中,我们使用导入内容在模块中,我们只需要为导入的绑定起一个名字我们也可以导入具名导出的内容。 ES6 模块系统 在 ES6 之前,我们已经知道了 RequireJS,AngularJS 的依赖注入,以及 CommonJS,具体可以看笔者的上一篇文章《JS...

    shmily 评论0 收藏0
  • ES6脚丫系列】模块Module

    摘要:命令用于规定本模块的对外接口。空格模块名字符串。其他模块加载该模块时,命令可以为该匿名函数指定任意名字。写法函数声明命令用在非匿名函数前,也是可以的。加载的时候,视同匿名函数加载。 本文字符数8200+,阅读时间约16分钟。 『ES6知识点总结』模块Module 第一节:Module基本概念 【01】过去使用CommonJS和AMD,前者用于服务器,后者用于浏览器。 Module可以取...

    gotham 评论0 收藏0
  • require,import区别

    摘要:,区别遵循的模块化规范不一样模块化规范即为提供一种模块编写模块依赖和模块运行的方案。出现的时间不同相关的规范由于野生性质,在年前后出生。作为的规范,一直沿用至今。这其实要感谢原来项目名叫做,后更名为这个神一般的项目。 require,import区别 遵循的模块化规范不一样 模块化规范:即为 JavaScript 提供一种模块编写、模块依赖和模块运行的方案。谁让最初的 JavaScri...

    Rango 评论0 收藏0
  • ES6 的模块系统

    摘要:的模块系统被设计成让你可以一次性引入多个变量。动态静态,或者说规矩和如何打破规矩作为一门动态编程语言,令人惊讶地拥有一个静态的模块系统。只要你的需求都是静态的话,这个模块系统还是很的。 此文为翻译,原文地址在这儿:https://hacks.mozilla.org/2015/08/es6-in-depth-modules/ ES6 是 ECMAScript 第 6 版本的简称,这是新一...

    MudOnTire 评论0 收藏0
  • 前端模块化详解

    摘要:提倡依赖前置,在定义模块的时候就要声明其依赖的模块。适用场景按需加载条件加载动态的模块路径注关于模块化,详细见阮一峰的入门模块与模块化区别模块化的规范和两种。 模块化开发方便代码的管理,提高代码复用性,降低代码耦合,每个模块都会有自己的作用域。当前流行的模块化规范有CommonJS,AMD,CMD,ES6的import/export CommonJS的主要实践者就是nodejs,一般...

    zhangfaliang 评论0 收藏0
  • 深入 CommonJs 与 ES6 Module

    摘要:目前主流的模块规范模块通用模块如果你在文件头部看到这样的代码,那么这个文件使用的就是规范实际上就是全局变量这三种风格的结合这段代码就是对当前运行环境的判断,如果是环境就是使用规范,如果不是就判断是否为环境,最后导出全局变量有了后我们的代码和 目前主流的模块规范 UMD CommonJs es6 module umd 模块(通用模块) (function (global, facto...

    sanyang 评论0 收藏0

发表评论

0条评论

wapeyang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<