Skip to content

02--ES6模块 #2

Open
Open
@simplexcspp

Description

@simplexcspp

一、ES6模块体系简述

  • 1、上一篇“ javascript模块化进程 ”中也说到:历史上,JavaScript 一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。ES6之前,社区制定了一些模块加载方案,最主要的有 CommonJS(服务器)和 AMD/CMD(浏览器)两种。

  • 2、ES6 在语言标准的层面上,实现了模块功能,完全可以取代 CommonJS 和 AMD(CMD) 规范,成为浏览器和服务器通用的模块解决方案

二、ES6模块

  • 1、ES6 模块与CommonJS 、 AMD 模块区别

    • ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量

    • CommonJS 和 AMD 模块,都只能在运行时确定模块依赖关系(运行时加载),因为只有运行时才能得到模块对应的对象(如,CommonJS 模块就是对象,输入时必须查找对象属性)。

    • ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入

  • 2、ES6 模块特性

    • 一个模块就是一个独立的文件,其内部的所有变量,外部无法获取

    • 编译时加载或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高

    • ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入,因此没法引用模块本身

  • 3、ES6模块构成的两个关键字

    • export: 规定模块的对外接口
    • import: 输入模块提供的功能
  • 4、export关键字

  • A、输出变量、函数、类

// 直接输出
export const name = 'jackxu';

export const add = (x = 0, y = 0) => {
    return x + y;
};

export class Hello {
    sayHi() {
        console.log('Hi~!');
    }
}

// 统一输出
const name = 'jackxu';

const add = (x = 0, y = 0) => {
    return x + y;
};

class Hello {
    sayHi() {
        console.log('Hi~!');
    }
}

export { name, add, Hello }

  • B、输出的变量就是原变量名,可以使用as关键字重命名
const name = 'jackxu';

const add = (x = 0, y = 0) => {
    return x + y;
};

class Hello {
    sayHi() {
        console.log('Hi~!');
    }
}

export {
    name as ESName,
    add as addTwo,
    Hello as Hi
}
  • 5、export使用注意事项

  • A、export规定模块的对外接口,必须与模块内部的变量建立一一对应的关系

// 错误写法
const add = (x = 0, y = 0) => {
    return x + y;
};

export add;
export 123;

image

//  正确写法
const add = (x = 0, y = 0) => {
    return x + y;
};

const A = 1;
export { add, A }
  • B、export命令可以出现在模块的任何位置,但必须处于模块顶层
const fn = () => {
    export const a = 'bar';
};

fn();

image

  • 6、import关键字

  • A、加载模块提供的功能(输入模块提供的功能)

import { name, add, Hello } form '模块相对路径/模块绝对路径/模块文件名'

模块后缀.js可以省略,相对路径./不能省略

模块文件名,由于不带路径,必须进行配置(如webpack+nodejs路径配置)

如加载先前export输出变量:

// 加载多个变量
import { name, add, Hello } form './class/test17';

// 加载单个变量
import { name } form './class/test17';
  • B、模块的整体加载:用星号 * 指定一个对象,所有输出值都加载在这个对象上面
import * as filters form '模块相对路径/模块绝对路径/模块文件名'

如整体加载先前export输出变量:

import * as test form './class/test17';

模块整体加载所在的那个对象(如上面test),应该是可以静态分析的,所以不允许运行时改变。

如修改先前export输出的函数add,虽然不会报错,但不应这么操作。

import * as test from './class/test17';

test.cname = '李四';  // 不恰当写法
test.add = () => 666;  // 不恰当写法
  • C、import命令具有提升效果,会提升到整个模块的头部,首先执行。

如先执行add,在import输入export输出的变量add

console.log(add(2));

import { add } from './class/test17';
  • D、import语句会执行所加载的模块,如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。
import '../../assets/styles/collect.css' // 仅仅执行模块,但是不输入任何值
  • E、import是静态执行,所以不能使用表达式和变量(这些只有在运行时才能得到结果的语法结构)

如下使用变量和表达式的import操作都会报错:

import { 'n' + 'ame' } from './class/test17';

image

let module = './class/test17';

import { name } from module;

image

const a = 1;

a === 1 ? import { name } from './class/test17' : '';

image

  • 7、export default关键字

export输出的模块,import加载的时,需要知道加载的变量名、函数名或类名,否则无法加载。而实际业务中,很可能不知道具体变量名,这时候就需要使用export default关键字。

  • A、export default输出的模块,使用import加载的时候,变量名可以任意指定名字,但import后面不使用{}
//  export default输出
const name = 'jackxu';

const add = (x = 0, y = 0) => {
    return x + y;
};

class Hello {
    sayHi() {
        console.log('Hi~!');
    }
}

export default { name, add, Hello }

// import 输入
import test from './class/test17';

console.log(test.name);
console.log(test.add(3, 6));

B、export default也可输出非匿名函数,系统默认函数名在模块外部无效,加载的时候视同匿名函数加载

匿名函数:

//  export default输出
export default (arr = []) => {
    return arr.filter(item => item > 6);
}

// import 输入
import filterArr from './class/test17';

console.log(filterArr([1, 4, 6, 8, 9, 10]));

非匿名函数:

//  export default输出
export default function filter_arr(arr = []) {
    return arr.filter(item => item > 6);
}

// import 输入
import filterArr from './class/test17';

console.log(filterArr([1, 4, 6, 8, 9, 10]));
  • C、export default用于指定模块的默认输出,一个模块只能有一个默认输出,因此export default命令只能使用一次
const _A = 123,
    _B = (...arg) => new Map().set('arg', arg);
    
export default _A;
export default _B;

image

  • D、export default本质: 输出一个名为default的变量或方法,然后系统允许为其任意取名

demo1:

// babel转码前
export default () => {
  console.log('山穷水尽,柳暗花明');
}

// babel转码后
'use strict';
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = function () {
  console.log('山穷水尽,柳暗花明');
};

demo2:

// babel转码前
const name = 'jackxu';
const fn = () => 5;
export default { name, fn };

// babel转码后
'use strict';
Object.defineProperty(exports, "__esModule", {
  value: true
});
var name = 'jackxu';
var fn = function fn() {
  return 5;
};
exports.default = { name: name, fn: fn };
  • E、export default其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句

错误写法:

export default const _B = 123;

image

正确写法:

const _B = 123;
export default _B;

// 对比export
export const _B = 123;
export default  66;

// 对比export
export 66;  // 错误写法

主要参考资料:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions