JS模块化,Javascript 模块化管理的历史
模块管理这个概念其实在前几年前端度过了刀耕火种年代之后就一直被提起。
直接回想起来的就是 cmd amd commonJS 这三大模块管理的印象。接下来,我们来详细聊聊。
一、什么是模块化开发
为了让一整个庞大的项目看起来整整齐齐,规规整整而出现的模块化管理,我们常见的三种模块化管理的库: requireJS、seaJS、commonJS规范 ( 注意,这里的commonJS不是一个库,而是一种规范) 逐渐的在我们日常的开发中出现。 同时依赖于 这三类规范而出现的一些构建工具,但最后都败给了 webpack 。这是一篇介绍 webpack 基本入门的文章,可以结合着这篇文章来进行解读。 《前端之路》之 webpack 4.0+ 的应用构建
1-1、模块化第一阶段
在这个阶段中,我们常常会把非常多复杂的功能 封装成一个个的函数:
- function f1() {
- // todo
- }
- function f2() {
- // todo
- }
- .
- .
- .
但是当整个项目变大了以后,就会遇到很多问题,都是定义的全局变量,形成了比较严重的污染,还有可能会出现因为重命名导致的各种问题。
所以这些是需要进化的。所以就会进入到模块化的第二阶段: 对象。
1-2、封装到对象
到了第二个阶段为了避免全局变量的污染,我们会将单个模块封装到一个对象内部。如下:
- const module = {
- _number: 10,
- f1: () => {
- console.log(123)
- },
- f2: () => {
- console.log(456)
- },
- .
- .
- .
- }
这样我们就设个模块定义一个对象,在需要的时候直接调用就好了,但是这样也会存在一个问题 这样写的话会暴露全部的对象内部的属性,
内部状态可以被外部改变
. 例如:
- module._number = 100
如果我们支付相关模块这样子来写的话。我们随意的来改变支付的金额,那样就会出现比较危险的情况。
1-3、 对象的优化
后来,聪明的人类就想到了利用 立即执行函数 来达到 不暴露私有成员的目的
- const module2 = (function() {
- let _money = 100
- const m1 = () => {
- console.log(123)
- }
- const m2 = () => {
- console.log(456)
- }
- return {
- f1: m1,
- f2: m2
- }
- })()
通过立即执行函数,让外部根本没有时间从外部去修改内部的属性,从而达到一定的防御作用。
以上就是模块化开发的基础中的基础。 没有库,没有规范,一切的维护都是靠人力,一切的创新,都是来源于 解放生产力。
二、模块化管理的发展历程
2-1、CommonJS
CommonJS 的出发点: JS 没有完善的模块系统,标准库较少,缺少包管理工具。(虽然这些东西,在后端语言中已经是 早就被玩的不想玩的东西了) 伴随着 NodeJS 的兴起,能让 JS 可以在任何地方运行,特别是服务端,以达到 也具备 Java、C#、PHP这些后台语言具备开发大型应用的能力,所以 CommonJS 应运而生。
2-1-1、 CommonJS常见规范
- 一个文件就是一个模块,拥有单独的作用域
- 普通方式定义的 变量、函数、对象都属于该模块内
- 通过
require
来加载模块 - 通过
exports
和module.exports
来暴露模块中的内容
我们通过编写一个 Demo 来尝试写这个规范
Demo 1 : 通过 module.exports 来导出模块
- // module.js
- module.exports = {
- name: "zhang",
- getName: function() {
- console.log(this.name);
- },
- changeName: function(n) {
- this.name = n;
- }
- };
- // index.js
- const module = require("./module/index");
- console.log(module) // {name: "zhang", getName: ƒ, changeName: ƒ} "commons"
Demo 2 : 通过 exports 来导出模块
- // module1.js
- const getParam = () => {
- console.log(a);
- };
- let a = 123;
- let b = 456;
- exports.a = a;
- exports.b = b;
- exports.getParam = getParam;
- // index.js
- const module1 = require("./module/index1");
- consoel.log(module1, "commons1") // {a: 123, b: 456, getParam: ƒ} "commons1"
Demo 3 : 同时存在 exports 和 module.exports 来导出模块
- // module2.js
- let a = 123;
- const getSome = () => {
- console.log("yyy");
- };
- const getA = () => {
- console.log(a);
- };
- exports.getSome = getSome;
- module.exports = getA;
- // index.js
- const module2 = require("./module/index2");
- consoel.log(module2, "commons2") // function getA() {...}
总结 : 通过这样的一个对比的例子就可以比较清晰的对比出 exports 和 module.exports 的区别: 1、当 exports 和 module.exports 同时存在的时候,module.exports 会盖过 exports 2、当模块内部全部是 exports 的时候, 就等同于 module.exports 3、最后 我们就可以认定为 exports 其实就是 module.exports 的子集。
以上就是我们对于 CommonJS 的一个初级的介绍。 还有一个硬性的规范,这里我们只是做一下列举,就不做详细的 Demo 演示了。
2-1-2、 CommonJS 规范 --- 加载、作用域
所有代码都运行在模块作用域,不会污染全局作用域;模块可以多次加载,但只会在第一次加载的时候运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果;模块的加载顺序,按照代码的出现顺序是同步加载的;
2-1-3、 CommonJS 规范 --- __dirname、__filename
__dirname代表当前模块文件所在的文件夹路径,__filename代表当前模块文件所在的文件夹路径+文件名;
2-2、CommonJS 与 ES6(ES2015) 的 import export
在 ES2015 标准为出来之前,最主要的是CommonJS和AMD规范。上文中我们已经介绍了 CommonJS 规范(主要是为了服务端 NodeJS 服务),那么当 ES6标准的出现,为浏览器端 模块化做了一个非常好的补充。
2-2-1、 ES6 的 export
export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口
Demo 1 export { xxx }
- // export/index.js
- const a = "123";
- const fn = () => window.location.href;
- export { fn };
- // show/index.js
- const ex = require("./export/index");
- import x from "./export/index";
- import { fn } from "./export/index";
- console.log(ex, "export1"); // {fn: ƒ, __esModule: true} "export1"
- console.log(x, "export-x"); // undefined "export-x"
- console.log(fn, "export-fn"); // function() { return window.location.href; } "export-x"
Demo 2 export default xxx
- // export/index1.js
- const a = "123";
- const fn = () => window.location.href;
- export default fn;
- // show/index1.js
- const ex1 = require("./export/index1");
- import x from "./export/index1";
- console.log(ex1, "export1");
- // {default: ƒ, __esModule: true} "export1"
- console.log(x, "export2");
- // ƒ fn() {return window.location.href;} "export2"
通过 Demo 1 和 Demo 2 我们可以很好的 对比了下 export 和 export default 的区别
export
可以导出的是一个对象中包含的多个 属性,方法。 export default
只能导出 一个 可以不具名的 对象。
import {fn} from './xxx/xxx'
( export 导出方式的 引用方式 ) import fn from './xxx/xxx1'
( export default 导出方式的 引用方式 )
同时,我们发现 可以直接使用 require 来引用
这个也能引用其实有点神奇的。但是功能和 import 一样。(原因就是我这里起了 webpack 的 server 相关)
2-2-2、 ES6 的 import
这里就同上面 Demo 中的例子一样了得出的结论就是
import {fn} from './xxx/xxx'
( export 导出方式的 引用方式 ) import fn from './xxx/xxx1'
( export default 导出方式的 引用方式 ,可以不用在意导出模块的模块名)
总结: 之前对于 模块的导出、引用 的概念都比较的魔幻,这次通过知识的梳理终于搞清楚了。
四、总结
4-1、 为什么会有这个东西?
方便组织你的代码,提高项目的可维护性。一个项目的可维护性高不高,也体现一个程序员的水平,在如今越来越复杂的前端项目,这一点尤为重要。
4-2、 为什么不用requirejs,seajs等
它们功能强大,但是文件体积是个问题,此外还有就是业务有时候可能没那么复杂。
4-3、 适用场景
移动端页面,将js注入到html页面,这样就不用考虑模块加载的问题,从而节省了很多的代码,在实现上也更为的简单。 如果是多文件加载的话,需要手动执行文件加载顺序,那么其实最好用库来进行依赖管理会好一点。
4-4、 现实情况
webpack + commonJS + ES6 (import + export )
这样来 实现模块管理,实现 较大项目的管理。 好了,模块化管理就先介绍到这里了,欢迎一起探讨
JS模块化,Javascript 模块化管理的历史的更多相关文章
- 应用require.js进行javascript模块化编程小试一例
长久以来都渴望应用javascript的模块化编程.今日紧迫更甚,岁月蹉跎,已经不能再等了. 拜读阮一峰的有关文章已经好几遍,文章写得真好,简洁流畅,头头是道,自觉有点明白了.但经验告诉我们,一定要亲 ...
- 利用require.js实现javascript模块化加载
这种引入很看到很想死吧! <script src="1.js"></script> <script src="2.js">& ...
- js模块化 javascript 模块化 闭包写法 闭包模块化写法
var main = main || {}; ; (function (main) { 'use strict'; //私有变量 var _s1 = 'Hello '; var _s2 = 'Worl ...
- 《前端之路》之 Javascript 模块化管理的来世今生
目录 第二章 - 04: Javascript 模块化管理的来世今生 一.什么是模块化开发 1-1.模块化第一阶段 1-2.封装到对象 1-3. 对象的优化 二.模块化管理的发展历程 2-1.Comm ...
- Javascript模块化编程(三):require.js的用法
Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...
- Javascript模块化编程之路——(require.js)
转自:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html Javascript模块化编程(一):模块的写法 随着网站逐渐变成&q ...
- javascript模块化编程库require.js的用法
随着javascript的兴起,越来越多的公司开始将JS模块化,以增加开发的效率和减少重复编写代码的.更是为了能更加容易的维护日后的代码,因为现在的随着人们对交互效果的越来越强烈的需求,我们的JS代码 ...
- (转)Javascript模块化编程(三):Require.js的用法
转自 ruanyifeng 系列目录: Javascript模块化编程(一):模块的写法 Javascript模块化编程(二):AMD规范 Javascript模块化编程(三):Require.js的 ...
- JavaScript模块化-require.js,r.js和打包发布
在JavaScript模块化和闭包和JavaScript-Module-Pattern-In-Depth这两篇文章中,提到了模块化的基本思想,但是在实际项目中模块化和项目人员的分工,组建化开发,打包发 ...
- 关于Javascript模块化和命名空间管理的问题说明
最近闲下来的时候,稍微想了想这个问题.关于Javascript模块化和命名空间管理 [关于模块化以及为什么要模块化] 先说说我们为什么要模块化吧.其实这还是和编码思想和代码管理的便利度相关(没有提及名 ...
随机推荐
- cf17B Hierarchy(额,,,水)
题意: Nick's company employed n people. Now Nick needs to build a tree hierarchy of «supervisor-surbod ...
- hdu 2201 熊猫阿波的故事(简单概率。。)
题意: 阿波上了飞机,飞机上有座位1,2,....,N.第i个乘客本应坐在第i个座位上. 可是阿波随便找了个座位就坐了下来,接下来大家也都随便找了个座位坐了下来. 问:第i个乘客坐到原座位的概率是多少 ...
- v-bind使用
v-bind基本使用 动态地绑定一个或多个属性,或者绑定一个组件 prop 到表达式. 语法:v-bind:属性名 = 属性值 <!-- 绑定一个 attribute --> <im ...
- Vue.js教程 2.体验Vue
Vue.js教程 2.体验Vue <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
- 从环境搭建到回归神经网络案例,带你掌握Keras
摘要:Keras作为神经网络的高级包,能够快速搭建神经网络,它的兼容性非常广,兼容了TensorFlow和Theano. 本文分享自华为云社区<[Python人工智能] 十六.Keras环境搭建 ...
- ELK 7.4.2 单机安装配置
Java环境准备 JDK下载 https://www.oracle.com/technetwork/java/javase/overview/index.html [root@manager ~]# ...
- 3、使用ListOperations操作redis(List列表)
文章来源:https://www.cnblogs.com/shiguotao-com/p/10560354.html 方法 c参数 s说明 List<V> range(K key, l ...
- 宝藏好物gRPCurl
宝物简介 grpcur是一个与grpc服务器交互的命令行工具,可认为是gRPC的curl工具. grpcurl用于从命令行调用gRPC服务器支持的RPC方法,gRPC使用二进制编码(protobuf) ...
- Android系统编程入门系列之硬件交互——多媒体摄像头
多媒体系列硬件 多媒体包括图片.动画.音频.视频,这些多媒体素材的采集(输入)主要依靠摄像头和麦克风等硬件设备转化为基础数据,而他们的播放渲染(输出),则需要依靠具有相关功能的编解码软件.当然随着硬件 ...
- stat命令的实现-mysate(必做)
学习使用stat(1),并用C语言实现 1. 提交学习stat(1)的截图 使用 man 1 stat 查看帮助手册 从图中可以看到stat的用法是display file or file syste ...