Loading

CommonJS 和ES6 MODULE的使用以及区别

CommonJS 使用方式

注意:是exports不是export

导出

 //通过module.exports导出一个对象,对象存放功能函数或数据或某个具体的值
//引入时通过自定义变量obj.fn1()使用即可
module.exports = { 
  fn1: function () {
    console.log("fn1")
  },
  flag: true,
  arr: [],
}

//亦可通过exports直接导出,exports本质上是node实现的module.exports的简写,相当于var exports = module.exports
exports.fn2 = function () {
  console.log("fn2")
}

function mod1(){console.log(1);}
function mod2(){console.log(2);}
module.exports={mod1:mod1,mod2:mod2}

引入

const express = require("express")      //express 是node第三方模块,直接引入模块名即可

const obj = require("模块文件路径")       // 引入自定义模块时,require函数的参数为模块的文件路径,引入了模块文件并赋值给自定义变量obj 

var {mod1,mod2} = require('./t');

ES6 MODULE使用方式

导出

第一种 - 直接导出
export var firstName = 'Michael';
export function multiply(x, y) { return x * y;};

第二种 - 使用{}导出
export { firstName, multiply };

注意:不可以直接导出export 1,也不可以直接export m

// 报错
export 1;

// 报错
var m = 1;
export m;

正确
// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

引入

import { firstName, lastName, year } from './profile.js';

别名
import { lastName as surname } from './profile.js';

注意:不允许在加载模块的脚本里面,改写接口。

可以直接理解成,通过ES6 MODULE引入的都是用const申明过。

import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only;
a.foo = 'hello'; // 合法操作

注意:如果想在一条import语句中,同时输入默认方法和其他接口,可以写成下面这样。

先写不带括号,再写带括号的

import _, { each, forEach } from 'lodash';

export default的使用

// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入

export default命令用在非匿名函数前,也是可以的。

非匿名
export default function foo() {
  console.log('foo');
}
匿名
export default function () {
  console.log('foo');
}

export 与 import 的复合写法

export { foo, bar } from 'my_module';

// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };

CommonJS和ES6 MODULE差异

  1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  2. CommonJS 模块是运行时加载(动态加载),ES6 模块是编译时输出接口(静态加载)。
  3. CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

ES2020支持import动态导入,详情

动态加载会得到的是一个promise对象,并且也支持await,这样就可以实现按需加载(懒加载)

import静态导入
import xxx from 'xxx.js'
import {xx,x} from 'xxx.js'

import动态导入
import(xxx.js)

动态导入和静态导入的区别

import在静态解析阶段执行,所以它是一个模块之中最早执行的,而动态这是在执行到对于代码时再去请求。

CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成,也就是说要运行全部代码才能确定module.exports的完整性。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成(按需加载)。

值的拷贝和值的引用的区别

import和require都是会执行一遍代码,只是一个是在运行时执行(耽误时间),一个是编译时解析(达到按需导入,优化运行速度)。

在两种方式都引入需要的内容时,不管是当做整体还是使用{}选取部分,CommonJS 模块输出的是值的拷贝,运行完模块后,值会缓存在本地,注意原始类型的值,会被缓存,函数不会缓存到本地,所以执行的时候还是去内存找到原本存储位置,这样才能改变模块中的内容,不然的话,及时写了一个如下面代码那样改变模块内容的代码,但是由于函数也被拷贝到了新内存中,这样就找不到需要改变的模块内的那个值了,那就表示模块写死了,无法改变,但事实并非如此。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值,除非采用刚刚说的方式。

CommonJS获取模块变动后的值

需要使用一个取值函数,不然会一直取到缓存好的值。

// lib.js
var counter_num = 3;
function incCounter() {counter_num++;}
function counter() {return counter_num}
module.exports = {counter,incCounter,};

var mod = require('./lib');
console.log(mod.counter());  // 3
mod.incCounter();
console.log(mod.counter()); // 4

ES6则如同是将引入文件中选择好的代码注入被引入文件里一样,JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。

换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

posted @ 2022-03-06 03:36  二柒的博客  阅读(249)  评论(0编辑  收藏  举报