JavaScript编码之路【ES6新特性之模块化】

简介: JavaScript编码之路【ES6新特性之模块化】

引子

欢迎来到 JavaScript 的模块化大战——这是一场被各种不同规范规定的模块横亘在我们面前带来的混乱战斗。然而,拿起你的剑吧,让我们一起跨过这段困难的旅程!

ES6(ECMAScript 2015)之前的规范

JavaScript社区存在多种模块化规范和实现


  • CommonJS ⭐⭐⭐⭐⭐
  • AMD(Asynchronous Module Definition)
  • UMD(Universal Module Definition)
  • IIFE(Immediately Invoked Function Expression)

CommonJS

在令人舒适的ES6(也就是 ECMAScript 2015)之前,我们的JavaScript社区里各种模块化规范和实现让人眼花缭乱。比如说CommonJS,这是一个专门针对服务器端JavaScript的模块化规范。要是你是个Node.js 的粉丝,你一定熟悉这个。它有两个特别简单术语——“require”和 “module.exports” 偶尔还会有个"exports",用这两个英勇的小家伙,你就可以加载和导出你的模块啦!


自创模块的导入导出

我们来看看他的第一件装备:module.exports

我们有两个模块,一个是math.js,用于进行数学运算,另一个是app.js,用于调用math.js中的函数。

首先,创建一个名为math.js的文件,并在其中定义一些数学函数:

math.js

它有 add 和 subtract 这两个超能力

加法函数

function add(a, b) {
  return a + b
}

减法函数

function subtract(a, b) {
  return a - b
}

然后我们把这些超能力暴露出去,让别人也可以得到这些超能力

module.exports = {
  add: add,
  subtract: subtract
}

app.js

引入math.js模块
有了这个,我们其他模块也可以有这个超能力
var math = require('./math')

看看我学会了新能力

使用加法函数

var result1 = math.add(10, 5)
console.log(result1) // 输出: 15

使用减法函数

var result2 = math.subtract(10, 5)
console.log(result2) // 输出: 5

看吧,是不是很神奇?只要你有心,你也可以!

而且这个英雄如此好学,他还多学会了一种叫做“exports”的装备,别小看它,它并不逊色于"module.exports"!

utils.js

我们有个模块叫做 utils.js,它有 sum 和 reverseString 这两个超能力

求和函数

function sum(numbers) {
  return numbers.reduce((acc, curr) => acc + curr, 0)
}

反转字符串函数

function reverseString(str) {
  return str.split('').reverse().join('')
}

然后我们用 exports 这个武器,暴露出去这些超能力

exports.sum = sum
exports.reverseString = reverseString

app.js

这样,其他模块想要这些超能力,只要去借就好了

var utils = require('./utils')

定义一组数字

var numbers = [1, 2, 3, 4, 5]

使用sum函数求和

var total = utils.sum(numbers)

console.log(total) // 输出: 15

使用reverseString函数反转字符串

var str = 'Hello World!'
var reversed = utils.reverseString(str)
console.log(reversed) // 输出: '!dlroW olleH'

是不是很厉害,就像是开了挂,来来去去就那么几行代码,动不动就能加载和导出任何模块,令人惊叹,这就是开挂的生活,我太羡慕了!


导入外部模块或第三方模块

等等,别急着去模仿英雄,除了自创超能力外,还有另一个技能——就是借用别人的超能力。没错,他叫做 CommonJS,他可以引入别人的超能力,把优秀的进行繁衍和传承,让强者更强。

相对路径引入

var http = require('http')

绝对路径引入

var myModule = require('/path/to/myModule')

使用模块的名称引入(需要先使用 npm 安装)

var moment = require('moment')
AMD(Asynchronous Module Definition)

在浏览器方面,我们逃不过另一个规范 —— 那就是 AMD (Asynchronous Module Definition)。这是专门针对浏览器端设计的,跟它名字一样,可以异步加载你的模块。它手里有两个武器 “define” 和 “require”,听起来跟CommonJS差不多,可实则不然,这娃子可是异步加载的,不像CommonJS那样会阻塞,性格活跃开朗,给它个大大的赞!

UMD(Universal Module Definition)

在上面这两个标准横行霸道的同时,出现了一位充满和平属性的 “UMD” (Universal Module Definition) 模块标准——综合了CommonJS和AMD, 还能在全局的JavaScript环境中工作。想想就觉得他好厉害,能在这几个环境中灵巧的折腾。但是他不出名,可能因为名字不好听吧。嘿嘿~


IIFE(Immediately Invoked Function Expression)

除此之外, IIFE(Immediately Invoked Function Expression ,立即调用的函数表达式),在 ES6 之前广泛用于模拟模块化。它不是一种明确定义的模块化规范,但却占据了 JavaScript 世界的大半江山。它的特点就是形成一块私有空间,变量不会污染全局。这一点,给它点个赞!


ES6的模块化语法

然后呢,那些派系斗争终于在ES6出现后告一段落。ES6的模块化标准走入了我们的视线。ES6的规范采用了一种更现代化、更强大的模块化特性,听到这你是不是心里一震,同时又对未知感到一丝恐惧呢?别怕,我来给你解释。

ES6的模块化功能主要由 export 和 import 这两个命令构成。 export 是英雄,用于定义模块的对外接口,而import就是小跟班,负责把其他模块的功能都统统引用过来。在在在在在在在,这里超级重要——“export default”,简单来说,它只能定义一个主角,不能搞出一堆 “皆大欢喜” 的场面出来。

  • export命令用于规定模块的对外接口
  • import命令用于输入其它模块提供的功能
暴露方式
命名导出
  • 分别导出
export A
export B
export C
export D
  • 统一导出
export {A, B, C, D}

首先,创建一个名为api.js的模块文件,用于封装使用axios进行网络请求的函数:

// api.js

import axios from 'axios';

// 获取用户列表
export function getUsers() {
  return axios.get('/api/users');
}

// 创建用户
export function createUser(user) {
  return axios.post('/api/users', user);
}

// 更新用户信息
export function updateUser(id, user) {
  return axios.put(`/api/users/${id}`, user);
}

// 删除用户
export function deleteUser(id) {
  return axios.delete(`/api/users/${id}`);
}

然后,在另一个文件中,比如main.js中,可以导入并使用这些命名导出的函数:

// main.js

import { getUsers, createUser, updateUser, deleteUser } from './api';

// 调用获取用户列表的函数
getUsers()
  .then(response => {
    console.log('用户列表:', response.data);
  })
  .catch(error => {
    console.error('获取用户列表失败:', error);
  });

// 创建新用户
const newUser = { name: 'John Doe', age: 30 };
createUser(newUser)
  .then(response => {
    console.log('创建用户成功:', response.data);
  })
  .catch(error => {
    console.error('创建用户失败:', error);
  });

// 更新用户信息
const userId = 123;
const updatedUser = { name: 'Jane Smith', age: 25 };
updateUser(userId, updatedUser)
  .then(response => {
    console.log('更新用户信息成功:', response.data);
  })
  .catch(error => {
    console.error('更新用户信息失败:', error);
  });

// 删除用户
const userIdToDelete = 456;
deleteUser(userIdToDelete)
  .then(response => {
    console.log('删除用户成功:', response.data);
  })
  .catch(error => {
    console.error('删除用户失败:', error);
  });
默认导出

export default

继续使用上面结合axios的例子

api.js

import axios from 'axios';

function getUsers() {
  return axios.get('/api/users');
}

function createUser(user) {
  return axios.post('/api/users', user);
}

function updateUser(id, user) {
  return axios.put(`/api/users/${id}`, user);
}

function deleteUser(id) {
  return axios.delete(`/api/users/${id}`);
}

export default {
  getUsers,
  createUser,
  updateUser,
  deleteUser
};

我们使用export default关键字将一个对象作为默认导出。注意,默认导出只能有一个。

然后,在另一个文件中,可以使用import api的形式来导入默认导出的模块:

import api from './api';

// 调用获取用户列表的函数
api.getUsers()
  .then(response => {
    console.log('用户列表:', response.data);
  })
  .catch(error => {
    console.error('获取用户列表失败:', error);
  });

// 创建新用户
const newUser = { name: 'John Doe', age: 30 };
api.createUser(newUser)
  .then(response => {
    console.log('创建用户成功:', response.data);
  })
  .catch(error => {
    console.error('创建用户失败:', error);
  });

// 更新用户信息
const userId = 123;
const updatedUser = { name: 'Jane Smith', age: 25 };
api.updateUser(userId, updatedUser)
  .then(response => {
    console.log('更新用户信息成功:', response.data);
  })
  .catch(error => {
    console.error('更新用户信息失败:', error);
  });

// 删除用户
const userIdToDelete = 456;
api.deleteUser(userIdToDelete)
  .then(response => {
    console.log('删除用户成功:', response.data);
  })
  .catch(error => {
    console.error('删除用户失败:', error);
  });

我们使用import api的语法导入了默认导出的模块,并将其命名为api。这样就可以直接使用api.getUsers、api.createUser等函数。


默认导出的好处是,在导入时不需要指定导出的名称,而是直接使用一个变量来引用整个导出模块。


引入方式

处女座可能会问,这多样性的导出方式,引入的时候会不会很痛苦啊?别怕,ES6的引入方式是非常人性化滴。

来来来,准备 m1 m2 m3 这三个模块

m1.js

对其分别暴露

export let school = '清华大学'

export function teacher() {
  console.log("开发 5 G")
}

m2.js

对其统一暴露

let school = '电子科技大学'
function fgo() {
  console.log("China")
}
export {school, go}

m3.js

对其默认暴露

export default {
  school: '北京大学',
  go: function() {
    console.log("去往北京大学")
  }
}
  1. 通用的导入方式

通用的导入方式:就类似你去货架上挑选商品,例如:import * as m1 from './src/js/m1.js' ,这里的*星号,代表着m1.js导出的所有模块,都通通归放到名为 m1 的这个变量中。

// 1. 引入 m1.js 模块内容
import * as m1 from './src/js/m1.js'
// 2. 引入 m2.js 模块内容
import * as m2 from './src/js/m2.js'
// 3. 引入 m3.js 模块内容
import * as m3 from './src/js/m3.js'
  1. 解构赋值形式

解构赋值形式:我就说嘛,JavaScript ES6 引入了这么现代化的特性,其中就肯定包括解构赋值啦。就比如:import {beauty} from './src/js/m4.js' ,这里的 {taech} 对你来说就是于从学校中精选你最喜欢的美女啦。


import {school, taech} from './src/js/m3.js'
import {school as otherSchool, teacher} from './src/js/m2.js'
import {default as m3} from './src/js/m3.js'
  1. 简写形式 【注意:只针对默认暴露】

简写形式:只针对默认暴露,听我说,这就类似于,作为一个孤胆英雄的模块,我就独自上场吧,那你作为引入方,直接用 import 声明一个变量,相应地引入我就行了。例如:import m3 from ‘./src/js/m3.js’ ,这种方式,简单粗暴,一目了然。

import m3 from './src/js/m3.js'

小结

嘿嘿,现在你有信心来驾驭这个 JavaScript 的模块化规范战场了吗?

目录
相关文章
|
26天前
|
存储 JavaScript 前端开发
JS的ES6知识点
【10月更文挑战第19天】这只是 ES6 的一些主要知识点,ES6 还带来了许多其他的特性和改进,这些特性使得 JavaScript 更加现代化和强大,为开发者提供了更多的便利和灵活性。
20 3
|
1月前
|
JavaScript 前端开发 编译器
掌握现代化JavaScript:ECMAScript提案与特性
【10月更文挑战第13天】本文介绍了ECMAScript(ES)的最新提案与特性,包括可选链、空值合并运算符、类字段和顶层Await等。通过跟踪TC39提案、使用Babel或TypeScript、测试兼容性以及逐步迁移,开发者可以高效地采用这些新特性,简化代码、提高开发效率并增强应用功能。文章还提供了实战技巧,帮助开发者在现代Web开发中充分利用这些现代化的特性。
|
1月前
|
JavaScript 前端开发 索引
JavaScript ES6及后续版本:新增的常用特性与亮点解析
JavaScript ES6及后续版本:新增的常用特性与亮点解析
37 4
|
1月前
|
自然语言处理 JavaScript 前端开发
JavaScript高级——ES6基础入门
JavaScript高级——ES6基础入门
25 1
|
20天前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
39 0
|
1月前
|
缓存 JavaScript 前端开发
Node.js模块化的基本概念和分类及使用方法
Node.js模块化的基本概念和分类及使用方法
34 0
|
JavaScript 安全 前端开发
JavaScript 编码风格指南
写作本文旨在加深自己印象,也为了更多人的了解到JS编码风格,提高自己的编码质量想了解更多的内容请阅读《编写可维护的JavaScript》 缩进 每一行的层级由4个空格组成,避免使用制表符 (Tab) 进行缩进 // 好的写法 if (true) { doSomething(); } 行的长度 每行长度不应超过80个字符。
992 0
|
JavaScript 前端开发 开发工具
JavaScript编码风格指南
程序语言的编码风格指南对于一个长期维护的软件而言是非常重要的;好的编程风格有助于写出质量更高、错误更少、更易于 维护的程序。 团队合作需要制定一些代码规范还有利用一些工具来强制要求团队代码的风格统一.毕竟很多情况下以后不一定是由写一手代码的人来维护代码,所以有一个统一的代码风格很重要!!!
862 0
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
97 2
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
130 4
下一篇
无影云桌面