exports与module.exports还有import

由于JavaScript缺乏模块体系,在ES6之前,社区指定了一些模块加载方案,比如node.js所遵循的commonJS规范。而在ES6在语言层面上实现了模块功能,完全可以取代现有的commonJS等规范,成为浏览器、服务器通用的模块解决方案。本篇博客目录如下:
1.如何使用exports
2.如何使用module.exports
3.exports与module.exports的区别
4.使环境支持module语法
5.export与export default的基本用法

1.如何使用exports

在es6还没有出现的日子里,通过commonJS实现模块加载会接触到两个方法,exports与module.exports。我们先来看exports,在node.js中,我们通常会以exports.name=something的形式来使用exports

//导出文件mout.js
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

exports.outputA=outputA;
exports.outputB=outputB;
//导入文件module.js
let mod=require("./mout.js");
console.log(mod);

这时会输出
这里写图片描述
如果你想在module.js中使用outputA或outputB函数,就得

let {outputA,outputB}=require("./mout.js");
//{}中变量名必须与mout.js导出函数名相同
outputA();
outputB();

上面的写法也等同于

let _mout=require("./mout.js");
//变量a,b的变量名可以随意
let a=_mout.outputA;
let b=_mout.outputB;
a();
b();

2.如何使用module.exports

在commonJS中还有一种方法可以导出模块。我们通常以module.exports=something的形式使用它

//还是那个导出文件
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

module.exports=outputA;
module.exports=outputB;
//还是那个导入文件
let mod=require("./mout.js");
console.log(mod);

这个时候我们会发现输出是这样子的
这里写图片描述
虽然我们在mout.js中module.exports两次,但输出却告诉我们只有最后一次module.exports是有效的,第一次module.exports被覆盖掉了。如果我们想在module.js中使用outputB只需mod()即可。
所以,当我们需要将模块定义为一个类时,使用module.exports是唯一的选择

3.exports与module.exports的区别

其实,module.exports 初始值为一个空对象 {}require() 返回的是 module.exports 而不是 exportsexports只不过是指向的 module.exports 的引用
赋给exports的所有属性或方法最终都赋值给了module.exports。但,这是有前提条件的,那就是module.exports是空对象,如果module.exports具有了一些属性或方法,那么赋给exports的所有属性或方法都会被忽略掉,譬如

//还是TA
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

exports.outputA=outputA;
module.exports=outputB;
//是TA是TA就是TA
let mod=require("./mout.js");
console.log(mod);

这样子,输出的就是酱紫的
这里写图片描述
而且无论exports在module.exports前还是后,结果都是module.exports生效,而exports看起来并没有发挥什么卵用。
通过上面的推导,我们可以猜测给module.exports添加属性等同于于给exports添加属性

//。。。。。
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

module.exports.outputA=outputA;
module.exports.outputB=outputB;
//。。。。。
let mod=require("./mout.js");
console.log(mod);

直接看结果
这里写图片描述
一目了然

4.使环境支持module语法

非常遗憾的是,到目前为止,node(v9.3.0)尚不支持module语法,但不久后的将来是一定能够实现的。为了让node等环境支持module语法,我们需要用到babel或者类似于babel的工具对代码进行编译。下面以babel为主进行讲解。
首先需要说明的是,如果你通过babel-node等工具试图直接在命令行中运行es6代码可能会出现错误。这是因为

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。而且像import和export这两个命令现在在任何浏览器中都是不支持的, 同时babel也无法将其转换为浏览器支持的ES5, 原因在于:babel只是个翻译,假设a.js 里 import 了 b.js, 对a.js进行转码,只是翻译了a.js,并不会把b.js的内容给读取合并进来, 如果想在最终的某一个js里,包含 a.js,b.js 的代码,那就需要用到打包工具

接下来就以webpack为例展示如何进行转码
首先,你得有个目录,并且你安装了node与npm
进入到目录中,运行npm init
init完了之后,执行npm install webpack --save-dev --no-optional
接下来,你需要安装babel-loader与babel-core

npm install --save-dev --no-optional babel-loader babel-core

然后根据你的需求选择转码规则,目前有这些
这里写图片描述
我们使用latest吧,npm install --save-dev --no-optional babel-preset-latest
之后我们还会用到path,所以一并安装上npm install --save-dev --no-optional path
目前为止,目录下的webpack.config.js应该是酱紫的
这里写图片描述

这一堆工作做完之后,我们还需要在根目录下创建一个webpack配置文件——webpack.config.js,具体内容如下

const path=require("path");
module.exports = {
  entry:  __dirname + "/app/import.js",//入口文件
  output: {
    path: __dirname + "/dist",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
  },
  module:{
    loaders:[
        {
            test:/\.js$/,
            loader:'babel-loader',//-loader不可省略
            include:path.resolve(__dirname,'/app'),//babel只处理指定目录
            options:{
                presets:['latest']
            }
        }
    ]
  }
}

其中,options字段值得我们注意。一般来说babel有三种配置方式:
通过webpack.config.js loaders中的options字段
通过package.json中的babel字段
通过.babelr文件
三种方式具体的配置内容是一模一样的,我比较喜欢第一种

这样子一通折腾下来后,我们在app下创建两个文件import.js与export.js。

//import.js
import {alias,outputB} from "./export.js"
console.log(alias);
console.log(outputB);
//export.js
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}

之后在根目录下运行webpack,等待打包完成之后,在dist目录下就会出现bundle.js,我们通过html引用也好,还是直接node运行都可以,输出结果是
这里写图片描述

5.export与export default的基本用法

普通的、老老实实的、朴实无华的操作

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA,outputB}
import {outputA,outputB} from "./export.js"
outputA()

在引入文件中,如果需要使用export.js中的函数,用户必须先知道它的名字,如果用户不想翻文档或者怎么滴,这样子就不太方便,所以就有了export default

function outputA(){
    console.log("this is output A");
}

export default outputB;
import alias from "./export.js"
console.log(alias);
alias();

注意,在import的时候,我们已经不用使用{}了
模块整体加载
如果我们需要加载模块的全部接口,那么只需

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA,outputB}
import * as alias from "./export.js"

export时使用别名

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}

接下来,我们进行一些比较骚气的操作

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}
export default outputB;

这段代码既有export又有export default
我们先

import * as x from "./export.js"
console.log(x);

这是,console出来的x是
这里写图片描述
这里我们可以看出export default的本质是输出一个叫做default的方法,系统允许我们对它取任意名称
接下来,酱紫

import x from "./export.js"
console.log(x);

输出结果是
这里写图片描述
也就是说,如果import时变量只有一个,而且外面没有{},那么该变量接受的就是export default。如果import时变量放在{}里,那么就会拿到对应的export。我们可以用这种方式同时接受export与export default

import x,{alias,outputB} from "./export.js"

猜你喜欢

转载自blog.csdn.net/wopelo/article/details/78890566