在ES6中使用什么语句实现模块的导入导出?

6 篇文章 0 订阅

前言

Es6之前,javascript没有模块系统,它无法将一个大程序拆分成若干个互相依赖的小文件,然后在用简单的方法拼装起来.为了做到模块化,Es6之前,引入了AMD(Asynchronous module definition)CMD(common module definition)

前者典型代表是requireJS(外国人搞出来的),后者是seajs(国内

共同点:都是对模块定义的不同规范,都是异步加载模块,并且解决文件之间的依赖重命名冲突等问题。 

不同点:模块定义的方式和模块加载机制是不同的,前者AMD(requirejs)是将所有文件同时加载,一次性引入,推崇依赖前置,也就是在定义模块时要先声明其依赖的模块,加载完模块后会立马执行该模块(运行时加载)

CMD(seajs)强调的是一个文件一个模块,可按需引入,推崇依赖就近,加载完某个模块后不会立即执行,而是等遇到了require语句的时候在执行 .

两者的使用加载机制不同,也就导致了AMD(requirejs)模块会提前执行,用户体验好,CMD(seajs)性能好,因为只有在需要时候才执行,在服务器端,nodejs使用的就是cmd规范,也就是需要什么包,就引入什么包,按需加入(编译时加载)

而在Es6的语言规格中引入了模块化功能,也就很好的取代了之前的commonjsAMD规范了,成为了浏览器和服务器的通用的模块解决方案,在现今(vuejs,ReactJS)等框架大行其道中,都引入了Es6中的模块化(Module)机制,一些自动化打包工具webpack或者微信小游戏中也同样如此

您将在本文中学习到什么是模块,以及模块的导入导出,理解了这个,在一些基于脚手架搭建的项目里或者自动化构建工具中,就不觉得写法怪怪和迷路了的

正文从这里开始~

 

什么是模块?

Es6中引入let,const定义变量是解决访问变量的全局作用域问题,从而引入块级作用域,解决命名冲突,同名全局污染,安全等问题

模块可以理解为函数代码块的功能,是封装对象的属性和方法的javascript代码,它可以是某单个文件,变量或者函数,

Es6模块中,无论有没有加"use strict",都会自动采用严格模式,而且在模块顶部创建的变量不会自动被添加全局作用域中,这个变量仅在模块的顶级作用域中存在,而且模块必须导出一些外部代码可以访问的元素,如变量或者函数,模块也可以从其他模块导入绑定

在模块与模块之间的特性与作用域关系不大(例如微信小程序或者小游戏中的各个文件就是不同的模块,在该文件定义的变量或者函数只在该文件内作用),但也很重要,在模块的顶部,this的值是undefined,另外,模块不支持HTML风格的代码注释

模块实质上是对业务逻辑分离实现低耦合高内聚,也便于代码管理而不是所有功能代码堆叠在一起,模块真正的魔力所在是仅导出和导入你需要的绑定,而不是将所有的东西都放到一个文件

引入模块与引入脚本是有区别的,前者更多是按需引入加载,后者而是无论有没有用,全部一次性引入和加载,类似于通过script标签引入jQuery等库都是一次性载入

Node中模块的导出与导入

Node模块中,采用的是commonjs规范,也就是使用require方式引入模块,而使用module.exports导出接口,node,例如如下代码example.js,当然你也是可以把属性值定义到外面去的,把下面这段代码存储脚本为example

/*
*  
通过module.exports将数据进行对外暴露
*/
module
.exports = {
      
name:"随笔川迹",
      
funA:function(){
         
return `我是${this.name}`
      }
}

// 或者把变量函数值定义在外面,例如,与上面等价,以下是常见写法
var name = "随笔川迹";
var funA = function(){
   
return `我是${name}`
}
module.exports = {
  
name:name,  // 至于前面的变量名可以任意,但是在另外一模块中引入时要与该变量名保持一致,否则就会报错,也可以只写一个name
  funA:funA  // 也可以只写一个funA
}

而在另外一文件命名requireExample.js中使用require方式引入

/*
*
*  
通过require()的方式将外部模块引入
*

*/

var  m =  require("./requireExample.js");
console.log(m.name);  // 随笔川迹
console.log(m.funA()); // 我是随笔川迹

 

 

以上代码是在node,通过module.exports对外暴露变量对象,函数等常见方式,而通过require()的方式引入本地模块或者导入包

这个module.exportsnode提供的一个私有全局变量属性,require也是node提供的一个私有全局方法,那么在Es6模块中并没有采用noderequire导入模块的方式

在微信小程序中,暂不支持Es6中的exportimport模块导出与导入的语法,它依然采用的是类似node中对外暴露数据用module.exports方式,而引入数据则用require的方式

注意:小程序中用import方式引入外部wxss是可以的,但在微信小游戏中却已经支持来Es6中的exportimport模块语法

如下为小游戏测试:Es6exportimport的使用,但遗憾的是在小程序暂且还不支持Es6中模块的写法,对外暴露数据仍然采用module.export 的方式而引入模块采用require的方式,与在node中使用相似

 

如何检测node.jsEs6的支持情况

命令行终端下全局安装 es-checker

npm install -g es-checker

安装后,在命令行中执行 es-checker命令

 

es-checker

在命令行终端就会有一个Es6在该node版本中支持结果:如下图所示,红色的表示是暂不支持的

 

exportimport的一个重要的限制是,他们必须在其他语句和函数之外使用,例如,下面的代码会给出一个语法错误

export语句不允许出现在if语句中,不能有条件导出或以任何方式动态导出,也就是说export命令规定的是对外的接口,必须与模块内部的变量建立一一对应的关系,不能这样写export 5;或者 var num = 5; export num;必须得加上大括号 {变量名}去暴露它 模块语法存在的一个原因是要让javascipt引擎静态的确定哪些可以导出,因此,只能在模块顶部使用export

同样,不能在一条语句中使用import,只能在顶部使用它(这也是为什么很多框架在业务逻辑代码之前,需要什么插件,都得提前引入),如下代码所示,import语句也不能放在一条语句当中

function testImport(){

     import flag  from "./ExportExample.js"   // 语法错误

 }

下面时在微信小游戏中测试可证

uploading.4e448015.gif转存失败重新上传取消uploading.4e448015.gif转存失败重新上传取消

由于同样的原因,不能动态的导入或导出绑定,exportimport关键字被设计成静态的 以上这种通过import导入模块与require的写法的具体区别是:

import 导入的方式更加灵活随意一些,要想用哪个变量,函数,模块就导入哪一个,按需加载,现在想想在使用框架当中,使用某个UI库里面的某单个组件,使用import导入单个组件而非全部一次性引入的原因了.

而使用require是全部都引入了的若想要更加效率的话,那么推崇import导入的方式 

1:全局完整引入,没有大括号,element-ui库中引入Element,当然在vue,还得Vue.use(插件名)全局注册一下

 

import Element from 'element-ui';
Vue.use(Element);

例2:从element-ui库中导入两个Button,Select组件

 

import { Button, Select } from 'element-ui
Vue.use(Button);
Vue.use(Select);

Es6中如何给导入导出时标识符重命名

从一个模块导入变量,函数或者类时,我们可能不希望使用他们的原始名称,就是导入导出时模块内的标识符(变量名,函数,或者类)可以不用一一对应,保持一致,可以在导出和导入过程中改变导出变量对象的名称

使用方式使用as关键字来指定变量,函数,或者类在模块外应该被称为什么名称 例如如下一函数

 

function sum(num1,num2){
    return num1+num2;
}

export {sum as add} // as后面是重新指定的函数名

如上代码,函数sum是本地名称,add是导出时使用的名称,换句话说,当另一个模块要导入这个函数时,必须使用add这个名称

若在importExample.js一模块中,则导入的变量对象应是add而不是sum,是由它导出时变量对象决定的

 

import  {add} from "./exportExample.js"

如果模块想使用不同的名称来导入函数,也可以使用as关键字

 

import {add as sum} from "./exportExample.js"
console.log(sum(1,2)); // 3
console.log(typeof add); // undefined

如上代码导入add函数时使用了一个导入名称来重命名sum函数,注意这种写法与前面导出export时的区别,使用import方式时,重新命名的标识符在前面,as后面是本地名称,但是这种方式,即使导入时改变函数的本地名称,即使模块导入了add函数,在当前模块中也没有add()标识符,如上对add的类型检测就是很好的验证

Es6中导入绑定时的一个注意点,导入定义时的变量无法更改

Es6中的import语句为变量,函数,类创建的目的是只读绑定所要导入的对象,并不是像正常变量一样简单的引用原始绑定,标识符只有在被导出的模块中可以修改(也就是只能在export模块中修改),当导入绑定的模块后,它是无法更改绑定的值的(import中无法对已导入绑定的变量作修改),from前面的就是绑定的变量对象,例如:如下代码所示

 

import {name,setName}  from "./exportExample.js"  // from前面双大括号中的变量对象是不可以被修改的,想尝试修改就会报错

console.log(name);  // 随笔川迹,此时访问name是全局变量
setName("好好先生");
console.log(name);  // 好好先生,函数内的同名变量会覆盖全局变量
name = "itclanCoder"  // 抛出错误,此处的name并非导入时name

uploading.4e448015.gif转存失败重新上传取消uploading.4e448015.gif转存失败重新上传取消

当想尝试更改导入时变量对象的名称时,就会抛出错误

uploading.4e448015.gif转存失败重新上传取消uploading.4e448015.gif转存失败重新上传取消

如上代码:当调用setName("好好先生")时会回到导出setName()的模块中去执行,并将name设置为好好先生,通过import导入的name标识符是export导出时的name标识符本地名称

总结

本文主要从什么是模块,Node中模块的导出与导入,如何检测node.jsEs6的支持情况 ,以及在Node中通过babeles6代码转化为Es5代码在Node中执行,模块的导出(导出数据,函数和类)模块的导入(单个导入,多个导入,导入整个)

模块中在用export关键字导出所要暴露的对象和用import关键字导入暴露的对象中,导入的变量对象需要和导出的保持一致,当然也可以通过as关键字进行重命名,并且模块导入的变量对象无法被改写,如果要改写,那么需要到export所暴露对象的模块中进行改写

 在模块化项目里,从模块中导出导入是如今非常常见的做法,如果在不给导出的标识符(变量,函数,),那么可以通过导出default关键字指定单个变量,函数或者类,预知后文详情,可持续关注了

关于模块化处理在未来的标准中非常重要,什么初次看到那些脚手架生成的代码,文件导出导入,有些摸不透的,不知所云的,就是因为加入了Es6中的模块化知识,AMD比较也好,还是CMD也罢,是有些区别的,本人初学者笔记学习心得,如果文章中有误导的地方,欢迎路过的老师多提意见和指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值