CommonJs与es6 module的区别

之前总是对模块机制类的内容走马观花,知其一不知其二,只了解AMD\CMD\Common.js很表面的知识,今天看到一篇大佬的文章,总结的很好,做个笔记以后方便查阅。

主流模块规范

1. UMD
2. CommonJs
3. es6 module

1. umd 模块(通用模块)
   (function (global,factory){
       typeof exports ==='object'&&typeof module !=='undefined'?module.exports=factory()
typeof define==='function'&& define.amd ? define(factory):(global.libName=factory())
   }(this,(function(){'use strict'})));

如果你在js文件头部看到这样的代码,那么这个文件使用的就是UMD规范,实际上就是amd+commonjs+全局变量这三种风格的结合。
这段代码就是对当前运行环境的判断,如果是Node环境就是使用CommonJs规范,如果不是就判断是否为AMD环境,最后导出全局变量
有了UMD后我们的代码和同时运行在Node和浏览器上,所以现在前端大多数的库最后打包都使用的是UMD规范

2. CommonJs
NodeJs环境所使用的模块系统就是基于CommonJs规范实现的,我们现在所说的CommonJs规范也大多是指Node的模块系统。
一、模块导出

关键字:module.exports exports

//foo.js
// 一个一个导出
module.exports.age=1
module.exports.foo=function(){}
exports.a='hello'

//整体导出
module.exports={age:1,a:'hello',foo:function(){}}

//整体导出不能用`exports` 用exports不能在导入的时候使用
exports={age:1,a:'hello',foo:function(){}}

这里需要注意exports不能被赋值,可以理解为在模块开始前exports=module.exports,因为赋值之后exports失去了对module。exports的引用,成为了一个模块内的局部变量

二、模块导入

关键字:require

  const foo=require('./foo.js')
  console.log(foo.age)//1
三、循环使用
 //a.js
 module.exports.a=1
 var b=require('./b')
 console.log(b)
 module.exports.a=2
//b.js
module.exports.b=11
var a=require('./a')
console.log(a)
module.exports.b=22

//main.js
var a=require('./a')
console.log(a)
3. ES6 module
ES6之前javascript一直没有属于自己的模块规范,所以社区制定了CommonJs规范,Node从CommonJS规范中借鉴了思想,于是有了Node的module,而AMD异步模块也同样脱胎于CommonJS规范,之后有了运行在浏览器上的require.js

es6 module基本语法:

export
 export * from 'module';
 export {name1,name2,....,nameN } from 'module';//重定向命名导出
 export {import1 as name1,import2 as name2,...,nameN } from 'module'; //重定向重命名导出
export {name1,name2,..,nameN};//与之前声明的变量名绑定 命名导出
export let name1='name1';//声明命名导出或者var,const,function,function*,class
export default expression;//默认导出
export default function(){...}//或者function*,class
export default function name1(){...}//或者function*,class
export { name1 as default,...};//重命名为默认导出

在这里插入图片描述

import
  //命名导出module.js
  let a=1,b=2
  export {a,b}
  export let c=3
 //命名导入main.js
 import {a,b,c} from 'module';//a:1 b:2 c:3
 import {a as newA,b,c as newC } from 'module';//newA:1 b:2 newC:3

 // 默认导出module.js
 export default 1
 
 // 默认导入 main.js
 import defaultExport from 'module';//defaultExport:1
 
 // 混合导出module.js
 let a=1
 export {a}
 const b=2
 export {b}
 export let c=3
 export default [1,2,3]

// module.js
Array.prototype.remove=function(){}

//副作用 只运行一个模块
import 'module';//执行module 不导出值 多次调用module.js只运行一次

//动态导入(异步导入)
var promise=import('module');

在这里插入图片描述

ES6 module 特点

1、ES6 module的语法是静态的
  • import会自动提升到代码的顶层
  • export和import只能出现在代码的顶层,下面这段语法是错误的
 // if for while 等都无法使用
 {
  export let a=1
  import defaultExport from 'module'
 }
 true || export let a=1

import的导入名不能为字符串或在判断语句,下面代码是错误的

 import 'defaultExport' from 'module'
 let name='Export'
 import 'default' + name from 'module'

静态的语法意味着可以在编译时确定导入和导出,更加快速的查找依赖,可以使用lint工具对模块依赖进行检查,可以对导入导出加上类型信息进行静态的类型检查

2、ES6 module的导出是绑定的
  • 使用import被导入的模块运行在严格模式下
  • 使用import被导入的变量是只读的,可以理解默认为const装饰,无法被赋值
  • 使用import被导入的变量是与原变量绑定/引用的,可以理解为import导入的变量无论是否为基本类型 都是引用传递
 //js中 基础类型是值传递
 let a =1
 let b=a
 b=2
 console.log(a,b) //1 2

//js中 引用类型是引用传递
let obj={name:'obj'}
let obj2=obj
obj2.name="obj2"
console.log(obj.name,obj2.name) //obj2 obj2

//es6 module 中基本类型也按引用传递
// foo.js
export let a=1
export function count(){
a++
}

// main.js
import {a,count} from './foo'
console.log(a)//1
count()
console.log(a)//2

// export default 是无法a的动态绑定 这一点跟CommonJs 有点相似 都是值的拷贝
let a=1;
export default a

// 可以用另一种方式实现default的动态绑定
let a=1;
export {a as default}
export function count(){
a++
}
// 就跟上面main.js一样

上面这段代码就是CommonJs导出变量和ES6导出变量的区别

3、ES module循环引用
 //bar.js
 import { foo } from './foo'
 console.log(foo);
 export let bar="bar"

//foo.js
import {bar} from './bar'
console.log(bar);
export let foo='foo'

// main.js
import {bar} from './bar'
console.log(bar)

1、执行main.js->导入 bar.js
2、bar.js->导入foo.js
3、foo.js->导入 bar.js-> bar.js已经执行过直接返回 ->输出 bar ->bar is not defined,bar未定义报错

我们可以使用function的方式解决:

//bar.js
import {foo} from './foo'
console.log(foo());
export function bar(){
return 'bar'
}

// foo.js
import { bar }  from './bar'
console.log(bar());
export function foo(){
 return 'foo'
}
//main.js
import {bar} from './bar'
console.log(bar)

因为函数声明会提示到文件顶部,所以就可以直接在foo.js调用还没执行完毕的bar.js的bar方法,不要在函数内使用外部变量,因为变量还未声明(let,const)和赋值,var

CommonJs和ES6 Module的区别

1、CommonJs导出的是变量的一份拷贝,ES6 Module导出的是变量的绑定(export default是特殊的)
2、CommonJs是单个值导出,ES6 Module可以导出多个
3、CommonJs是动态语法可以写在判断力,ES6 Module静态语法只能写在顶层
4、CommonJs的this是当前模块,ES6 Module的this是undefined

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值