车栈

ES2015入门系列11-模块 Modules

看一下官方介绍:

Language-level support for modules for component definition.

JS在ES2015开始原生支持模块化开发,我们之前也曾借助于诸如:

  • AMD
  • CommonJS

等的模块加载器进行过模块化开发,我想说的是那些都没有今天要讲的简单好用。

⚠️ 警告,正式版中的ES2015中没有模块加载器,所以我们依然需要之前的模块加载器帮助我们。

先来介绍下语法(官方示例代码):

//lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

//app.js
import * as math from 'lib/math';
import {sum, pi} from 'lib/math';
console.log("2π = " + math.sum(math.pi, math.pi));
  • 模块中对象暴露

只需要 export xx 即可,可以是任何类型的对象。

  • 从模块中导入

使用 import 即可, 几种方式

  • import * as xx from ..

    导入某个模块下的所有到某个命名空间下,如示例代码中的 import * as math from ’lib/math’, 意即将lib/math下所有暴露的对象导入到math对象下,之后就可以只用math.xxx访问了。

  • import {x, y, z} from ..

    手动导入模块下某个对象,x, y, z 需要和模块中定义的名字对应,顺序无关。

略微有点啰嗦了是吧?来看下面这种:

//lib/math.js
export default function (x, y) {
  return x + y;
}
//app.js
import sum from 'lib/math';

这样以来,写法上简单了许多,如果有default,也有其他的export怎么办呢?如下:

import default, {other1, other2} from 'someMoule';

一般在开发中,只暴露一个default的情况占大多数。

还有一个叫 export *, 用来在某个模块内将另一个模块的暴露的对象在这个模块重新暴露出去,个人觉得用处不是很大,不做过多描述。

下面,我们继续实战,依然是在ES2015入门系列10-类 classes中写的游戏,我们是在一个文件里运行的,下面我们将代码进行分拆成几个文件,进入模块化开发:

使用ES2015入门系列9-Babel和Rollup的配置,我们的目录结构如下:

  • es2015-learning
    • dist
    • src
      • Game.js
      • Hero.js
      • main.js
      • Monster.js
      • Role.js

Game.js 代码

import Monster from './Monster.js';
import Hero from './Hero.js';

export default class Game { //游戏世界

  constructor() {
    this.name = "权利的游戏";
    this.hero = new Hero('Jon Snow', 10); // 初始化英雄Jon Snow
    this.monsters = [ //怪物集合,模拟简单的游戏关卡。
      new Monster('异鬼 01', 1, 10),
      new Monster('异鬼 02', 3, 30),
      new Monster('异鬼 03', 5, 50),
      new Monster('异鬼 04', 10, 100),
      new Monster('异鬼 05', 15, 150),
      new Monster('异鬼 06', 20, 200),
      new Monster('Night King', 50, 500)
    ];
    this.level = 0; // 游戏当前关卡记录
    console.log(`你在[${this.name}]中扮演[${this.hero.name}], 征程即将开始...`);
  }

  play() { // 游戏开始
    while (this.level < this.monsters.length && ! this.hero.isDead()) {
      let monster = this.monsters[this.level];
      console.log(`关卡[${this.level + 1}] 你遇到了[${monster.name}], 进入战斗:`);
      let offensive = this.hero;
      let defensive = monster;
      while (! this.hero.isDead() && ! monster.isDead()) {
        offensive.attack(defensive);
        let middleman = offensive;
        offensive = defensive;
        defensive = middleman;
      }
      if (this.hero.isDead()) {
        console.log(`你被[${monster.name}]打败了, 游戏结束!`);
        break;
      }
      if (monster.isDead()) {
        console.log(`你打败了[${monster.name}] 等级提升:[${monster.level}]`);
        this.hero.levelUp(monster.level);
        this.level ++;
      }
    }
    if (this.level === this.monsters.length) {
        console.log(`恭喜你通关游戏!`);
    }
  }

}

Hero.js 代码

import Role from './Role.js';

export default class Hero extends Role {

    attack(role) { //攻击,有概率是用必杀攻击
        if (! this.isCriticalStrike()) {
            return this.criticalStrike(role);
        }

        return this.strike(role);
    }

    criticalStrike(role) { //必杀攻击
        let power = parseInt(200 * Math.random() + 50);
        role.damage(power);
        console.log(`[${this.name}]使用必杀攻击了[${role.name}], 造成了[${power}]点伤害`);
    }

    isCriticalStrike() {
        return Math.random() > 0.70;
    }

}

Monster.js 代码

import Role from './Role.js';

export default class Monster extends Role {

}

Role.js 代码

export default class Role { //角色基类

  constructor(name, level = 1, health = 100) {
      this.name = name;
      this.level = level;
      this.health = health;
  }

  isDead() { //判断角色是否死亡
    return this.health <= 0;
  }

  levelUp(level = 1) { //升级
    this.level += level;
  }

  damage(power) { //受到伤害
    this.health = this.health - power;
  }

  attack(role) { //攻击
    this.strike(role);
  }

  strike(role) { //普通攻击
    let power = parseInt(Math.random() * 20 * this.level / 10);
    role.damage(power);
    console.log(`[${this.name}]攻击了[${role.name}], 造成了[${power}]点伤害`);
  }

}

最后, main.js 代码

import Game from './Game.js';

new Game().play();

一切准备就绪,执行:

npm run build

将编译后的dist/main.js,放入网页中,运行,Yeah!It works!

恭喜,我们一起学会了ES2015带给我们的模块化开发!

Keep on hacking!