Es6中的模块化Module,导入(import)导出(export)
栏目: JavaScript · 发布时间: 7年前
内容简介:前言如果你想阅读体验更好直戳链接在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()); // 我是随笔川迹
复制代码
执行结果如下图所示
这个 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模块化
- 前端模块化总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
XML Hacks
Michael Fitzgerald / O'Reilly Media, Inc. / 2004-07-27 / USD 24.95
Developers and system administrators alike are uncovering the true power of XML, the Extensible Markup Language that enables data to be sent over the Internet from one computer platform to another or ......一起来看看 《XML Hacks》 这本书的介绍吧!
XML 在线格式化
在线 XML 格式化压缩工具
HEX HSV 转换工具
HEX HSV 互换工具