Es6中的模块化Module,导入(import)导出(export)
栏目: JavaScript · 发布时间: 6年前
内容简介:前言如果你想阅读体验更好直戳链接在Es6之前,javascript没有模块系统,它无法将一个大程序拆分成若干个互相依赖的小文件,然后在用简单的方法拼装起来.为了做到模块化,在Es6之前,引入了AMD(Asynchronous module definition)与CMD(common module definition)
前言
如果你想阅读体验更好直戳链接 Es6中的模块化module导入(import)导出(export)
在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的语言规格中引入了模块化功能,也就很好的取代了之前的commonjs和AMD规范了,成为了浏览器和服务器的通用的模块解决方案,在现今(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.exports是node提供的一个私有全局变量属性,而require也是node提供的一个私有全局方法 ,那么在Es6模块中并没有采用node中require导入模块的方式
在微信小程序中,暂不支持Es6中的export和import模块导出与导入的语法,它依然采用的是类似node中对外暴露数据用module.exports方式,而引入数据则用require的方式,勾选了微信开发者工具底下Es5转Es6,使用Es6中模块化,仍然会报错
注意:小程序中用import方式引入外部wxss是可以的,但在微信小游戏中却已经支持来Es6中的export与import模块语法
如下为小游戏测试:Es6中export与import的使用,但遗憾的是在小程序暂且还不支持Es6中模块的写法,对外暴露数据仍然采用module.export 的方式而引入模块采用require的方式,与在node中使用相似
如何检测node.js对Es6的支持情况
命令行终端下全局安装 es-checker
npm install -g es-checker 复制代码
安装后,在命令行中执行 es-checker命令
es-checker 复制代码
在命令行终端就会有一个Es6在该node版本中支持结果:如下图所示,红色的表示是暂不支持的
另外一种检测Es6的方法是:在node的repl环境中测试,如果不支持就会报错,运行正常就说明支持Es6写法
还有一种检测方法就是:参考官方文档Es6对Node或者浏览器的支持情况具体可Ecmascript6 compatibility Table(https://kangax.github.io/compat-table/es6/),微信不支持访问外链,直接将地止复制到浏览器访问即可
Es6中模块导出的基本语法
模块的导出,export关键字用于暴露数据,暴露给其他模块
使用方式是,可以将export放在任何变量,函数或类声明的前面,从而将他们从模块导出,而import用于引入数据,例如如下所示
将下面这些js存储到exportExample.js中,分别导出的是数据,函数,类
/* * * @authors 随笔川迹 (itclanCode@163.com) * @date 2018-07-07 18:01:23 * @desc:导出数据 * */ // 导出数据 export var name = "随笔川迹"; // 导出暴露name变量 export let weChatPublic = "itclanCoder"; // 暴露weChatPublic export const time = 2018; // 暴露time // 导出函数 export function sum(num1,num2){ return num1+num2; } /* * * 以上等价于 * function sum(num1,num2){ * return num1+num2; * } * export sum; * */ // 导出类 export class People{ constructor(name,age){ this.name = name; this.age = age; } info(){ return `${this.name}${this.age}岁了`; } } 复制代码
若将上面代码进行拆分
1. 导出数据,变量前面加上export关键字
export var name = "随笔川迹"; export let weChatPublic = "itclanCoder"; export const time = 2018; // 上面的等价于下面的写法,以下这种是常见写法 var name = "随笔川迹"; let weChatPublic = "itclanCoder"; const time = 2018; export {name,weChatPublic,time} 复制代码
2. 导出函数,函数前面加上export关键字
export function sum(num1,num2){ return num1+num2; } 复制代码
也可以这样:在定义它时没有马上导出它,由于不必总是导出声明,可以导出引用,因此下面这段代码也是可以运行的
function sum(num1,num2){ return num1+num2; } // 之后将其导出 export sum; 复制代码
注意:一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取,同样,任何未显示导出的变量,函数或类都是模块私有的,若没有用export对外暴露,是无法从模块外部访问的 例如:
function countResult(num1,num2){ return num1-num2; } // 没有通过export关键字导出,在外部是无法访问该模块的变量或者函数的 复制代码
3. 导出类,类前面加上export关键字
export class People{ constructor(name,age){ this.name = name; this.age = age; } info(){ return `${this.name}${this.age}` } } 复制代码
对应在另一个模块中通过import导入如下所示,模块命名为importExample.js
/* * * @desc:从exportExample模块中导入数据,通过import的方式 * @说明:由于我在node环境中测试,因为node暂且不支持Es6中的module语法,所以得先把es6代码通过babel转化成Es5代码,方可在node环境中执行该脚本,from后面具体路径引入的应该是通过Es6转化为Es5的代码 * */ import { name, weChatPublic,time,sum,People} from "../modelTest1/exportExampleEs5.js" var people = new People("小美",18); // 实例化perople对象 console.log(name); console.log(weChatPublic); console.log(time); console.log(sum(1,2)); console.log(people.info()); 复制代码
**注意1:**在上面的示例中,除了export关键字外,每一个声明与脚本中的一模一样,因为导出的函数和类声明需要有一个名称,所以代码中的每一个函数或类也确实有这个名称,除非用default关键字,否则不能用这个语法导出匿名函数或类
注意2:因为在现今node版本环境中,目前还不直接支持export和import语法,也就是说在node环境中,直接写Es6的模块代码,用node执行js脚本,会抛出错误,所以得先把Es6转换成Es5版本的代码,然后在node环境下运行该脚本才不会报错,这种转换方式可以通过babel进行转化
安装babel如下所示:命令行终端下通过npm全局安装babel-cli
npm install --global babel-cli npm install --save babel-preset-es2015 复制代码
然后在当前目录下新建配置文件.babelrc,注意存储的位置不要带有中文路径,否则使用babel命令时会抛出错误
{ "presets":["es2015"] } 复制代码
在编写好es6代码后通过 babel Es6源脚本 -o Es5脚本 这里的-o或--out-file指的从Es6标准格式转化生成的输出Es5文件
让我们对比看一下,其实在node中Es6中的export通过babel编译后Es5中代码是以exports方式进行导出的,而Es6中的import导入模块通过babel编译后是通过转变为require的方式引入的:
如下对比所示:Es6中export导出模块代码
/* * * @authors 随笔川迹 (itclanCode@163.com) * @date 2018-07-07 18:01:23 * @desc:导出数据 * */ // 导出数据 export var name = "随笔川迹"; // 导出暴露name变量 export let weChatPublic = "itclanCoder"; // 暴露weChatPublic export const time = 2018; // 暴露time // 导出函数 export function sum(num1,num2){ return num1+num2; } /* * * 以上等价于 * function sum(num1,num2){ * return num1+num2; * } * export sum; * */ function multiply(num1,num2){ return num1+num2; } export multiply; // 导出类 export class People{ constructor(name,age){ this.name = name; this.age = age; } info(){ return `${this.name}${this.age}岁了`; } } 复制代码
通过babel编译转变为Es5代码
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); exports.sum = sum; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* * * @authors 随笔川迹 (itclanCode@163.com) * @date 2018-07-07 18:01:23 * @desc:导出数据 * */ // 导出数据 var name = exports.name = "随笔川迹"; // 导出暴露name变量 var weChatPublic = exports.weChatPublic = "itclanCoder"; // 暴露weChatPublic var time = exports.time = 2018; // 暴露time var flag = true; // 导出函数 function sum(num1, num2) { return num1 + num2; } /* * * 以上等价于 * function sum(num1,num2){ * return num1+num2; * } * export sum; * */ // 导出类 var People = exports.People = function() { function People(name, age) { _classCallCheck(this, People); this.name = name; this.age = age; } _createClass(People, [{ key: "info", value: function info() { return "" + this.name + this.age + "\u5C81\u4E86"; } }]); return People; }(); 复制代码
而在另一个模块中importExample.js中,这里是Es6中import导入模块的代码
/* * * @desc:从exportExample模块中导入数据,通过import的方式 * */ import { name, weChatPublic,time,sum,People} from "../modelTest1/exportExampleEs5.js" var people = new People("小美",18); // 实例化perople对象 console.log(name); console.log(weChatPublic); console.log(time); console.log(sum(1,2)); console.log(people.info()); 复制代码
在node中通过babel编译转化为Es5代码后,import相当于require的作用,但是他们两者是不同的,前者是按需引入,而后者是一次性全部引入
"use strict"; var _exportExampleEs = require("../modelTest1/exportExampleEs5.js"); var people = new _exportExampleEs.People("小美", 18); // 实例化perople对象 /* * * @desc:从exportExample模块中导入数据,通过import的方式 * */ console.log(_exportExampleEs.name); console.log(_exportExampleEs.weChatPublic); console.log(_exportExampleEs.time); console.log((0, _exportExampleEs.sum)(1, 2)); console.log(people.info()); 复制代码
Es6中模块导入的基本语法·
如果想从一个文件(模块)访问另一个文件(模块)的功能,则需要通过import关键字在另一个模块中引入数据,import语句的两个部分组成分别是:要导入的标识符和标识符应当从那个模块导入,另外,导入的标识符的顺序可以是任意位置,但是导入的标识符(也就是大括号里面的变量)与export暴露出的变量名应该是一致的 具体的写法如下:
import {identifer1,indentifer2} from "./example.js" // import {标识符1,标识符2} from "本地模块路径" 复制代码
import后面的双大括号表示从后面给定的模块导入的绑定,关键字from表示从哪个模块导入给定的绑定,该模块由表示模块路径的字符串指定(被称为模块说明符),如果在浏览器中,使用路径格式与
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Android模块化改造以及模块化通信框架
- Laravel 模块化开发模块 – Caffienate
- ASP.NET Core模块化前后端分离快速开发框架介绍之4、模块化实现思路
- 前端模块化架构设计与实现(二|模块接口设计)
- JavaScript模块化
- 前端模块化总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ppk on JavaScript, 1/e
Peter-Paul Koch / New Riders Press / 2006-09-20 / USD 44.99
Whether you're an old-school scripter who needs to modernize your JavaScripting skills or a standards-aware Web developer who needs best practices and code examples, you'll welcome this guide from a J......一起来看看 《ppk on JavaScript, 1/e》 这本书的介绍吧!