JavaScript进阶(十二):JS 模块化编程规范-CommonJS、AMD、CMD

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

require()函数加载math模块的时候,就会先加载dependenceModule模块。当有多个依赖时,就将所有的依赖都写在define()函数第一个参数数组中,所以说AMD是依赖前置的。这不同于CMD规范,它是依赖就近的。
CMD

三、CMD-同步模块定义

CMDCommon Module Definition通用模块定义,是SeaJS在推广过程中对模块定义的规范化产出,是一个同步模块定义,是SeaJS的一个标准,SeaJSCMD概念的一个实现,SeaJS是淘宝团队玉伯提供的一个模块开发的js框架。CMD规范是国内发展出来的,就像AMD有个requireJSCMD有个浏览器的实现SeaJSSeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。

CMD 通过define()定义,没有依赖前置,通过require加载jQuery插件,CMD是依赖就近,在什么地方使用到插件就在什么地方require该插件,即用即返,这是一个同步的概念。

CMD 规范中,一个模块就是一个文件。代码的书写格式如下:

define(function(require, exports, module) {
// 模块代码
});

其中,

  • require是可以把其他模块导入进来的一个参数;
  • exports是可以把模块内的一些属性和方法导出的;
  • module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。

AMD是依赖关系前置,在定义模块的时候就要声明其依赖的模块;
CMD是按需加载依赖就近,只有在用到某个模块的时候再去require,示例代码如下:

// CMD
define(function(require, exports, module) {
var a = require(‘./a’)
a.doSomething()
// 此处略去 100 行
var b = require(‘./b’) // 依赖可以就近书写
b.doSomething()
// …
})

// AMD 默认推荐的是
define([‘./a’, ‘./b’], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()

})

四、CommonJS 规范

CommonJS规范是通过module.exports定义的,在前端浏览器里面并不支持module.exports,通过node.js后端使用。Nodejs端使用CommonJS规范,前端浏览器一般使用AMDCMDES6等定义模块化开发规范。

CommonJS的终极目标是提供一个类似PythonRubyJava的标准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用就可以运行在不同的JavaScript解释器和不同的主机环境中。

在兼容CommonJS的系统中,你可以使用JavaScript开发以下程序:

  1. 服务器端JavaScript应用程序;
  2. 命令行工具;
  3. 图形界面应用程序;
  4. 混合应用程序(如,Titanium或Adobe AIR);

2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程。这标志"Javascript模块化编程"正式诞生。NodeJSCommonJS规范的实现,webpack 也是以CommonJS的形式来书写。

node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。假定有一个数学模块math.js,就可以像下面这样加载。

var math = require(‘math’);

然后,就可以调用模块提供的方法:

var math = require(‘math’);

math.add(2,3); // 5

CommonJS定义的模块分为:模块引用(require)模块定义(exports)模块标识(module)
其中,

  • require()用来引入外部模块;
  • exports对象用于导出当前模块的方法或变量,唯一的导出口;
  • module对象就代表模块本身。

虽说NodeJS遵循CommonJS的规范,但是相比也是做了一些取舍,添了一些新东西的。

NPM作为Node包管理器,同样遵循CommonJS规范。

下面讲讲commonJS的原理以及简易实现:

1、原理
浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境变量。

module
exports
require
global

只要能够提供这四个变量,浏览器就能加载 CommonJS 模块。

下面是一个简单的示例。

var module = {
exports: {}
};

(function(module, exports) {
exports.multiply = function (n) { return n * 1000 };
}(module, module.exports))

var f = module.exports.multiply;
f(5) // 5000

上面代码向一个立即执行函数提供 module 和 exports 两个外部变量,模块就放在这个立即执行函数里面。模块的输出值放在 module.exports 之中,这样就实现了模块的加载。

2、Browserify 的实现
Browserify 是目前最常用的 CommonJS 格式转换工具。

请看一个例子,main.js 模块加载 foo.js 模块。

// foo.js
module.exports = function(x) {
console.log(x);
};

// main.js
var foo = require(“./foo”);
foo(“Hi”);

使用下面的命令,就能将main.js转为浏览器可用的格式。

$ browserify main.js > compiled.js

其中,Browserify到底做了什么?安装一下browser-unpack,就清楚了。

$ npm install browser-unpack -g

然后,将前面生成的compile.js解包。

$ browser-unpack < compiled.js

[
{
“id”:1,
“source”:“module.exports = function(x) {\n console.log(x);\n};”,
“deps”:{}
},
{
“id”:2,
“source”:“var foo = require(”./foo");\nfoo(“Hi”);“,
“deps”:{”./foo":1},
“entry”:true
}
]

可以看到,browerify 将所有模块放入一个数组,id 属性是模块的编号,source 属性是模块的源码,deps 属性是模块的依赖。

因为 main.js 里面加载了 foo.js,所以 deps 属性就指定 ./foo 对应1号模块。执行的时候,浏览器遇到 require('./foo') 语句,就自动执行1号模块的 source 属性,并将执行后的 module.exports 属性值输出。

五、ES6

有关es6模块特性,强烈推荐阮一峰老师的:ECMAScript 6 入门 - Module 的语法专栏。

要说 ES6 模块特性,那么就先说说 ES6 模块跟 CommonJS 模块的不同之处。

  • ES6 模块输出的是值的引用,输出接口动态绑定,而 CommonJS 输出的是值的拷贝;
  • ES6 模块编译时执行,而 CommonJS 模块总是在运行时加载。

CommonJS 模块输出的是值的拷贝(原始值的拷贝),也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

// a.js
var b = require(‘./b’);
console.log(b.foo);
setTimeout(() => {
console.log(b.foo);
console.log(require(‘./b’).foo);
}, 1000);

// b.js
let foo = 1;
setTimeout(() => {
foo = 2;
}, 500);
module.exports = {
foo: foo,
};
// 执行:node a.js
// 执行结果:
// 1
// 1
// 1

上面代码说明,b 模块加载以后,它的内部 foo 变化就影响不到输出的 exports.foo 了。这是因为 foo 是一个原始类型的值,会被缓存。所以如果你想要在 CommonJS 中动态获取模块中的值,那么就需要借助于函数延时执行的特性。

// a.js

总结

阿里十分注重你对源码的理解,对你所学,所用东西的理解,对项目的理解。

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ttps://img-blog.csdnimg.cn/img_convert/04656be82d9b13ba32131bdc8ec55836.png)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-q51ESACo-1713686931603)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值