前端基础整理 | require / exports / import / export

一、 模块规范

一句话总结:CommonJs用于服务端Node.js中,AMD和CMD是针对客户端的规范,为了不让引入依赖阻塞了代码进行,使用了异步加载模块。

1. CommonJs:

  • 适用区域:用于服务端。
  • 导入:require
  • 导出:module.exportsexports
  • exports与module.exports
    exportsmodule.exports的引用,var exports = module.exports = {};,而最终导出的是仍然是module.exports,因此,倘若更改exports的指向,最终返回的仍然是module.exports
  • 用法:

module.exports 基础用法

/* export.js */
const a = 1
module.exports = a
/* import.js */
var a = require('./export')
// a = 1

exports 基础用法

/* export.js */
exports.a = 1 // 不能改变引用, exports = {a:1}
/* import.js */
var a = require('./export')
// a = {a:1}

可以使用es6的特性 - 解构赋值

/* export.js */
exports.a = 1
/* import.js */
var {a} = require('./export')
// a = 1
  • 为什么不适用于客户端?
    同步引用不适用于客户端场景
var _ = require('./loadsh')
_.map([1,2,3], square)

如上面所示,如果loadsh这个库由于网络原因加载得很慢的话,那么它便阻塞了后面代码的运行,这样对用户体验牺牲很大。
这时候AMD就有了诞生的需求了。

2. AMD:

AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

  • 使用define定义模块:
// id:模块名(可选),dependencies:依赖库(可选),factory工厂方法,返回一个模版函数
define(id?, [dependencies?], factory)
// demo
define(['Lib'], function(Lib){
  function foo(){
    Lib.doSomething();
  }
  return {
    foo : foo
  };
});
  • 使用require加载模块,因为是回调执行,所以不阻塞啦。
// module:加载的模块数组, callback:加载成功后再执行的回调函数
require([module], callback);
// demo
require([loadsh], loadsh.map([1,2,3],square))

目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。

3. CMD:

CMD (Common Module Definition), 是seajs推崇的规范。它与AMD最大的区别是它推崇依赖就近。

  • 同样,CMD使用define定义模块
// id:模块名(可选),dependencies:依赖库(可选),factory工厂方法,返回一个模版函数
define(id?, [dependencies?], factory)
// 不同点:它可以在工厂函数中导出导入(也是通常的做法),也是它推崇的导出导入方式
define(function(require, exports, module) {
// 模块代码
  var $ = require('jquery.js')
  $('div').addClass('active');
});
  • 用use加载模块
// 加载模块
seajs.use(['myModule.js'], function(my){
});
  • 与AMD的区别:
    最明显的区别就是在模块定义时对依赖的处理不同
    1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
    2、CMD推崇就近依赖,只有在用到某个模块的时候再去require
    这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法
    AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同。
    AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行
    CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的

二. ES6

这里主要介绍:

  • ES6的import和export和export default的基本用法
  • ES6和CommonJs的混用

1. 基本用法

/* export.js */
export const a = 1
/* import.js */
import { a } from './export'
// a = 1

经过babel的转换。可以看到转化为exports->require,并且给exports添加了一个__esModule的属性。

/* export.js */
"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.a = void 0;
const a = 1;
exports.a = a;
/* import.js */
"use strict";
var _export = require("./export");
console.log(_export.a);

export default

// export.js
const b = 2
export default b
// import.js
import b from './export'
console.log(b)

通过babel转化,使用exports.default进行导出。

/* export.js */
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
const b = 2;
var _default = b;
exports.default = _default;

⚠️注意:不能认为 import { b } from './export' 是用了解构赋值。当执行以下代码是不行的。import 语句中的"解构赋值"并不是解构赋值,而是 named imports。

// import.js
import { {a} } from './export' // 语法错误
console.log(a)
// export.js
export const b = { a: 1 }

named imports,语法上和解构赋值很像,但还是有所差别,比如下面的例子。

import { b as a } from './export' // 解构赋值中不能用 as

因此还是得老老实实把值接下来,然后再去处理。或者你可以和CommonJs混用来达到类似解构赋值的效果。

2. 与CommonJs混用

由于babel解析的时候也是解析成exports->require形式的,因此可以和commonJs混用。

  • import.js / require - export.js / export
// import.js
var { b } = require('./export').default
console.log(b)
// export.js
export default {
  b: 2
}
  • import.js / import - export.js / exports
// import.js
import { a } from './export'
console.log(a)
// export.js
module.exports = {
  a: 1
}

你可能感兴趣的:(前端基础整理 | require / exports / import / export)