前言 🛰🛰
我们在无论是在查阅别人的代码,还是在实际项目开发的过程中,肯定都会使用导入导出的功能,有时候我们会搞混这几种方式到底有什么区别,今天我们就来细致的区分一下:
导入导出方式⚔️⚔️
我们都知道最常见的几种导出方式无非是export
,exports
,export default
,module.exports
这几种,常见的导入方式则就是import
和require
,那么他们到底有什么区别呢?我们一起来看一下:
最为新手小白的我们在看到第一眼的时候肯定会一脸懵,其实我们可以将他们根据不同的JavaScript规范来分开来看
export和export default
export
和export default
是ES6的规范:
这两种方式其实没有什么本质的区别,我们一起来看一下示例:
使用export default这种导出方式叫做默认导出(暴露)
var name = "小明"; var fun = function () { console.log(name); }; export default { name, fun }; ----------------------- export default function() { console.log ('export 不能这样子') }
这里我们可以看到我们声明了一个函数,里面打印了变量name的值,然后我们使用export default导出了一个函数对象,也可以直接默认的导出一个函数。
值得注意的是,在一个js文件中只能有一个export default
,不能重复的书写,否则会报错,而我们在接收这个导出的对象的中的内容的时候我们需要使用import
来进行导入。
几个容易错误的点:
export default const name3 = 'error'; //这样导出的方式是错误的 ----------------------- var name3="小红"; export default name3;//这样是正确的
当然接收导出的值的时候也需要注意
import
接收导出的值:
我们在使用export default
导出的时候我们在接受值的时候需要注意
import text from "app.js"
我们假设需要导出内容的是app.js这个文件,我们在接收的时候可以自己定义一个变量名称,就像示例中的test,当然如果想要获取导出对象中的内容就可以使用解构的语法。这一点与export
是有区别的
export
导出示例:
var age=20; var open=true; export {age,open} //等同于下边 export {age} export {open} export const fun=()=>{console.log("hhh")} export const age1 = 23 //let 也行
在export中我们可以一口气导出多个变量或者对象,函数等而且我们也可以向最后一行代码那样在导出的时候定义变量名称,有一点需要注意使用export导出的内容必须有名称,就比如导出函数的时候不能像默认暴露那样直接导出一个匿名函数。
导入时的注意点:
import {age,open} from "app.js" import {fun} from "app.js" import {age1 as age2} form "app.js"
这里要注意我们在导入的时候一定要加上花括号,而且花括号中的名称必须和导出的变量或者函数名称一样,这一点时与export default不同的,还有我们导入在age1可以将其重命名为age2.
module.export 和exports
首先这两种方式是基于Common.js
的规范来定义的,而这个规范是在Node.js中,因此这两种方式主要是在Node.js中使用
在上下文中提供了exports对象
用于导出当前模块的方法或者变量,他是唯一导出的出口,当然在模块中还存在module对象
,他代表模块自身,exports就是module的属性(默认的值是一个空对象),而在Node.js中一个文件就是一个模块,所以我们导出
在模块之中上下文提供require来引入外部的模块,
首先我们先来查看module.exports这种方式。
const a = 1; const fun = () => { console.log(2); }; module.exports = { a, fun };
var req = require ('../app.js'); console.log(req.a1,req.a) //1 [Function: fun]
我们在导出的时候需要注意导出的先后循序,当然这也可以当作面试出题,比如一下这几行代码导出的先后顺序不一样就会打印出不同的值,我们可以一起来看一下:
const a = 1; const fun = () => { console.log(2); }; // console.log(fun); module.exports.a2 = 4; module.exports = { a, fun };
const req = require("./module.exports"); console.log(req.a, req.fun, req.a2); //1 [Function: fun] undefined
为什么会有undefined呢?
我们在开始的时候说了我们其实发通过exports这中方式默认是导出一个空的对象,所以我们通过module.exports.a2这种方式导出其实是在这个空的对象上面添加了一个a2属性并且值为4,但是下来通过module.exports导出的时候,我们通过赋值的方式将之前的对象给覆盖了,因此之前的a2值就没有了,
同样如果我们给这两种导出的方式换一下先后顺序,比如我们这样写
module.exports = { a, fun }; module.exports.a2 = 4;
我们就可以获取到a2的值,因为我们先进行了对象的覆盖,然后在新对象上面增加了一个a2的属性并且值为4。
exports导出
其实exports
是module.exports
的一个引用,可以认为是 var exports = module.exports
我们来讲解一下他们二者的区别:
- 直接赋值和替换对象的行为不同:
module.exports = value;
:将module.exports
直接赋值为一个新的值,这个新值会成为模块的导出内容。例如:module.exports = { a: 1 };
,地址发生了改变直接替换之前的所有内容。exports.key = value;
:将一个新的属性和值添加到exports
对象中。例如:exports.a = 1;
module.exports
优先级高于exports
:
- 如果在模块中同时使用
module.exports
和exports
,那么最终导出的内容以module.exports
为准。也就是说,exports
对象的变化不会影响最终导出的内容。
使用exports的误区
直接上一个例子来给大家演示一下:
const a = 1; const fun = () => { console.log(2); }; exports = { a, fun };
const req = require("./module.exports"); console.log(req); console.log(req.a, req.fun); //{} //undefined undefined
为什么会出现这种情况呢?
我们知道在最初的时候module.exports
和exports
最初是指向同一个对象,也就是他们的地址是相同的,但是在这里我们通过对象给exports
赋值的时候实际上已经改变了exports
的地址,但是module.exports
还是默认的地址指向还是一个空的对象,而我们执行导出的时候实际上还是通过module.exports
,所以最终还是导出了一个空对象。
因此我们在module.exports
和exports
混用的时候要注意地址的问题,不要直接改变module.exports
的地址,如果直接改变了,那么exports的操作就会不生效,如果你想混用,那最好全部用module.exports.x = xxx和exports.xx = xxxx这种写法,这样的写法就没有改变默认的地址。
exports.a2 = 4; module.exports.fun = fun; module.exports.a = a; -------------------- const req = require("./module.exports"); console.log(req); //{ a2: 4, fun: [Function: fun], a: 1 }
这样就可以正常的获取到导出的内容。
总结📖📖
经过这次的总结学习,相信你一定熟悉了各种的导出导入方式,以及他们之间的区别。所以我认为学习要从细节入手,见微知著这样才能发现以前所不了解的,才能有所进步。