javascript模块化

javascript模块化也不是一天两天了,但是随着技术的发展,常用的模块化方式也就那几种,正所谓数风流模块还看今朝,所以就来对比一下当下使用比较多的commonJS和es6标准中提出的模块化方式。

commonJS

commonJS作为Node.js的模块化规范,一直沿用至今,而node现在没办法直接兼容es6的模块化规范,只能通过一些第三方的库将es6的模块化规范转化为commonJS规范。

这个引发的一个情况让我困惑了好久,当初在看别人的项目时或者自己写一些项目的时候,发现有些地方用的是require对包进行引入,有些地方用的是import进行引入。但是这两个却能达到相同的功能。后面总结了一下,发现所有的通过import引入库的代码都是自己写的… 而所有的通过require引入的都是一些配置文件上的…通过import引入的是es6标准,通过require引入的是commonJS标准。

因为babel的存在,我们在平时用到commonJS的机会并不多,但是node.js支持的是commonJS,我们用的各种工具都会用到,所以还是要稍微了解一下。

在commonJS标准下 require/exports的使用方法如下:

const fs = require('fs')
const {fs}=require('fs')//没见人这么用过...不过经过试验确实可行,类似es6中引入单个模块,不建议使用
exports.fs = fs
module.exports = fs

用起来还是很简单的,通过require导入模块,exports输出接口。在require一个模块时,执行整个模块,然后生成一个对象。以后用到这个模块的时候就从这个对象上取值,而且即使再执行一次require也不会再次执行这个模块,而是直接到缓存中取值。

由于require并不会动态的去加载模块,就导致模块中的内容发生变化后,在引入的模块中并不会体现。如:

//counter.js 
exports.count = 0;
 setTimeout(() => {
     console.log("in counterjs count increse to " + ++exports.count);
 }, 500);
//commonjsTest.js
var {count} = require('./counter');
setTimeout(() => {
    console.log("read count in commonjs " + count);
}, 1000);

输出:

in counterjs count increse to 1
read count in commonjs 0

可以看到,在counter.js中的count值已经变成了1,而在commonjsTest.js中的count并没有动态的变化。如果我们换一种引用方法:

var counter = require('./counter');
setTimeout(() => {
    console.log("read count in commonjs " + counter.count);
}, 1000);

输出:

in counterjs count increse to 1
read count in commonjs 1

这次引用了一个模块,而不是模块中的单个属性,可以看到这个属性竟然动态的变化了。

这是因为在commonJS中是通过值传递或者引用传递的方式实现模块化的,所以当我们引入的是一个模块时,传入的就是这个模块的引用,所以当counter.js中count的值变化后,指向count的引用的值也变了。而当我们引入单个模块时,由于count是是Number类型的数据,所以传的是值而不是引用。并且require并不会去动态的读取,就导致了两边的变量的值没有统一。

因此,为了使得在使用require的情况下动态的获取到模块中的属性值,建议在获取基本类型的变量时,将其包到对象中,通过传递引用的方式获取。

ES6模块化

es6中的模块化通过 import/export 来实现,主要写法如下:

import fs from 'fs'
import {default as fs} from 'fs'
import * as fs from 'fs'
import {readFile} from 'fs'
import {readFile as read} from 'fs'
import fs, {readFile} from 'fs'

export default fs
export const fs
export function readFile
export {readFile, read}
export * from 'fs'

读取和输出的方式多种多样,不再一一介绍,具体用法可以查阅文档。

es6的模块是动态引用的,而不是简单的传值,所以不会出现和commonJS一样的问题

同样举个例子说明一下:

//counteres6.js
export var count = 0;
setTimeout(() => {
    console.log("in counteres6js count increse to " + ++count);
}, 500);
//es6.js
import {count} from './counteres6'
setTimeout(() => {
    console.log("count = " + count);
}, 1000);

执行es6.js输出:

in counteres6js count increse to 1
count = 1

可以看到,即使是基本类型,es6的传值也是动态 引用的。

一个更加强有力的说明:

1536224918931

上面是babel对es6代码的转换,可以看到即使是基本类型,为了动态的统一,转换之后的代码也是通过对象的方式整个使用的。

总结

es6的模块化通过动态引用的方式解决了commonJS中可能出现的不统一的问题。在使用commonJS时,需要注意避免单个的传值的引用。也希望node 能尽快的兼容es6的模块化标准,这样就不用一套代码中出现两套标准了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值