资讯专栏INFORMATION COLUMN

前端模块化详解

zhangfaliang / 800人阅读

摘要:提倡依赖前置,在定义模块的时候就要声明其依赖的模块。适用场景按需加载条件加载动态的模块路径注关于模块化,详细见阮一峰的入门模块与模块化区别模块化的规范和两种。

模块化开发方便代码的管理,提高代码复用性,降低代码耦合,每个模块都会有自己的作用域。当前流行的模块化规范有CommonJS,AMD,CMD,ES6的import/export

CommonJS的主要实践者就是nodejs,一般对模块输出用module.exports去输出,用require去引入模块,CommonJS一般采用同步加载【require / module.exports / exports】

AMD遵从RequireJs规范,推崇依赖前置(提前执行)【require / defined】

CMD遵从SeaJs规范,推崇依赖就近(延迟执行)【require / defined】

ES6 可静态分析,提前编译,不是在运行时确认【import / export】

发展历程

简单封装 -> 命名空间/modules -> script loader/modules loader -> 同步加载CommonJS/AMD/CMD -> ES6 import export/export default -> 模块打包工具browserify/webpack

简单封装

用法:把不同的函数简单地放在一起,看作一个模块
缺点:

"污染"了全局变量,无法保证不与其他模块发生变量名冲突;

模块成员之间看不出直接关系

对象(命名空间)

用法:把功能代码放入对象中,当作对象的属性
优点:减少了全局上的变量数目,避免变量全局污染
缺点:本质是对象,而这个对象会暴露所有模块成员,内部状态可以被外部改写

立即执行函数(IIFE)

声明一个匿名函数

马上调用这个匿名函数

作用:创建一个独立的作用域。数据是私有的, 外部只能通过暴露的方法操作
这个作用域里面的变量,外面访问不到(即避免「变量污染」)

CommonJS

导入导出:require & exports/module.exports
主要实践者:NodeJS

模块导入
语法:require(module)

eg:
var math = require("math");
math.add(2, 3);

如果模块输出的是一个函数,那就不能定义在exports对象上面,而要定义在module.exports变量上面。

// example2.js
module.exports = function () {
    console.log("hello world")
}
        
// main.js 
require("./example2.js")()
AMD(Asynchronous Module Definition)

提倡依赖前置,在定义模块的时候就要声明其依赖的模块。在requireJs推广过程中产生的规范

模块定义
define(id?, dependencies?, factory)
id:字符串,模块名称(可选)
dependencies:数组,是我们要载入的依赖模块(可选),使用相对路径
factory:工厂方法,返回一个模块函数

模块导入
require([module], callback)
module:是一个数组,里面的成员就是要加载的模块
callback:则是加载成功之后的回调函数

requireJS 优点

实现js文件的异步加载,避免网页失去响应;

管理模块之间的依赖性,按照依赖关系加载,便于代码的编写和维护。

采用异步方式加载模块,通过define来定义一个模块,通过require来引入模块,模块的加载不影响后面语句的执行,所有依赖于这些模块的语句都写在一个回调函数中,加载完毕后,这个回调函数才运行

CMD(Common Module Definition)

提倡就近依赖(按需加载),在用到某个模块的时候再去require进来。在Sea.js推广过程中产生的规范

模块定义
define(id?, dependencies?, factory) 与AMD类似

// eg
define("hello", ["jquery"], function(require, exports, module) {
   // 模块代码
   // return 模块对象
});

模块导入导出
与 AMD 类似

ES6

导入导出:import/export/export default

export defalut

默认输出是一个函数/变量
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字
需要注意的是,这时import命令后面,不使用大括号

// export-fn.js 
export default function () {
    console.log("foo");
}

import foo from "export-fn.js"

export default命令也可以用在非匿名函数前,视同匿名函数加载

export default 命令用于指定模块的默认输出。一个模块只能有一个默认输出,因此export default 命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字

export & export default区别

使用export default时,对应的import语句不需要使用大括号,默认输出
使用export时,对应的import语句需要使用大括号

// 第一组 export default
export default function crc32() { // 输出
    // ...
}
import crc32 from "crc32"; // 输入


// 第二组 export 
export function crc32() { // 输出
    // ...
};
import {crc32} from "crc32"; // 输入
ES6、AMD和CommonJS区别

ES6模块使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
CommonJS 和 AMD 模块,都只能在运行时确定这些东西;
CommonJS 模块就是对象,输入时必须查找对象属性

CommonJS模块

 let { stat, exists, readFile } = require("fs")

整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”

ES6模块

import { stat, exists, readFile } from "fs"

从fs模块加载 3 个方法,其他方法不加载,这种加载称为“编译时加载”或者静态加载

CommonJS模块

const path = "./" + fileName
const myModual = require(path)

动态加载,require到底加载哪一个模块,只有运行时才知道

import()

动态加载,正在提案阶段,import()返回一个 Promise 对象
import()加载模块成功以后,这个模块会作为一个对象,当作then方法的参数
import()类似于 Node 的require方法,区别主要是前者是异步加载,后者是同步加载。

适用场景
(1)按需加载
(2)条件加载
(3)动态的模块路径

注:关于ES6模块化,详细见 阮一峰的es6入门 module模块

es6 与 commonJS/AMD 模块化区别

模块化的规范:CommonJS和AMD两种。前者用于服务器,后者用于浏览器。

而ES6 中提供了简单的模块系统,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。

require与import的区别(commonJS与ES6模块化区别)

require/exports是CommonJS的一部分;import/export是ES6的新规范
require支持 动态导入,import不支持,正在提案 (babel 下可支持)
require是 同步 导入,import属于 异步 导入
require是 值拷贝,导出值变化不会影响导入值;import是值引用,指向 内存地址,导入值会随导出值而变化

参考:
前端工程师必备:前端的模块化
阮一峰的es6入门 module模块

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103938.html

相关文章

  • 新上课程推荐:《React Hooks 案例详解(React 进阶必备)》

    摘要:课程制作和案例制作都经过精心编排。对于开发者意义重大,希望对有需要的开发者有所帮助。是从提案转为正式加入的新特性。并不需要用继承,而是推荐用嵌套。大型项目中模块化与功能解耦困难。从而更加易于复用和独立测试。但使用会减少这种几率。 showImg(https://segmentfault.com/img/bVbpNRZ?w=1920&h=1080); 讲师简介 曾任职中软军队事业部,参与...

    Lin_YT 评论0 收藏0
  • ES6之路之模块详解

    摘要:例如我们导入模块,可以这么导入桃翁欢迎关注公众号前端桃园报错不能定义相同名字变量报错,不能重新赋值小猪可以看到导入绑定这里不理解绑定,文章后面会解释时,形式类似于对象解构,但实际上并无关联。 欢迎访问个人站点 简介 何为模块 一个模块只不过是一个写在文件中的 JavaScript 代码块。 模块中的函数或变量不可用,除非模块文件导出它们。 简单地说,这些模块可以帮助你在你的模块中编写...

    huashiou 评论0 收藏0
  • 用WEB技术栈开发NATIVE应用(二):WEEX 前端SDK原理详解

    摘要:依旧采取传统的开发技术栈进行开发,同时在终端的运行体验不输。首先来看下前端开发框架目前与构成了三大最流行的前端开发框架,具有组件化以及三大特性,还学习的,引入了状态管理模块。 摘要: WEEX依旧采取传统的web开发技术栈进行开发,同时app在终端的运行体验不输native app。其同时解决了开发效率、发版速度以及用户体验三个核心问题。那么WEEX是如何实现的?目前WEEX已经完全开...

    ls0609 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<