We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
模块化是将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并组合在一起。块(文件)的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
在没有模块化之前,前端将不同的功能封装到不同的全局函数中,如下:
function f1(){ ....} function f2(){.....}
那么带来的问题就是:
为了解决这个问题,出现了namespace模式,如下:
let myNamespace = { data:"www.baidu.com", f1() {... } } //通过namespace避免污染命名空间 myNamespace.f1()
但是以上方法仍然存在问题: 数据不安全。例如,可以直接修改里面的data
myNamespace.data = 'other data'
为了解决这个问题,出现了IIFE(Immediately-invoked function expression 立即执行函数表达式)模式,如下:
// index.html文件 <script type="text/javascript" src="module.js"></script> <script type="text/javascript"> myModule.foo() myModule.bar() console.log(myModule.data) //undefined 不能访问模块内部数据 myModule.data = 'xxxx' //不是修改的模块内部的data myModule.foo() //没有改变 </script>
// module.js文件 (function(window) { let data = 'www.baidu.com' //操作数据的函数 function foo() { //用于暴露有函数 console.log(`foo() ${data}`) } function bar() { //用于暴露有函数 console.log(`bar() ${data}`) otherFun() //内部调用 } function otherFun() { //内部私有的函数 console.log('otherFun()') } //暴露行为 window.myModule = { foo, bar } //ES6写法 })(window)
由于module中的data没有暴露,所以是不可修改的,代码myModule.data只会在window.myModule这个对象上新增一个data的属性。 但是以上方法仍然存在一个问题,如果module模块需要依赖其他模块怎么办? 需要对IIFE进行增强,如下:
// index.html文件 <!-- 引入的js必须有一定顺序 --> <script type="text/javascript" src="jquery-1.10.1.js"></script> <script type="text/javascript" src="module.js"></script> <script type="text/javascript"> myModule.foo() </script>
// module.js文件 (function(window, $) { let data = 'www.baidu.com' //操作数据的函数 function foo() { //用于暴露有函数 console.log(`foo() ${data}`) $('body').css('background', 'red') } function bar() { //用于暴露有函数 console.log(`bar() ${data}`) otherFun() //内部调用 } function otherFun() { //内部私有的函数 console.log('otherFun()') } //暴露行为 window.myModule = { foo, bar } })(window, jQuery)
以上就是前端的模块化
IIFE增强版的模块化实际上已经实现了前端的模块化,它带来的好处包括
但是IIFE增强版的模块化带来了新的问题,比如:
为了解决这两个问题,出现了模块化规范,比如 CommonJS, AMD, ES6, CMD规范。
基本语法:
//暴露模块 module.export = value 或 export.xxx = value //引用模块,如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径 require("xxx")
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。例:
// example.js var x = 5; var addX = function (value) { return value + x; }; module.exports.x = x; module.exports.addX = addX;
上面代码通过module.exports输出变量x和函数addX。
//如果参数字符串以“./”开头,则表示加载的是一个位于相对路径 var example = require('./example.js'); console.log(example.x); // 5 console.log(example.addX(1)); // 6
require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。这点与ES6模块化有重大差异(下文会介绍)
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
基本语法:
//定义没有依赖的模块 define(function(){ return 模块 }) //定义有依赖的模块 define(['module1', 'module2'], function(m1, m2){ return 模块 }) //引用模块使用 require(['module1', 'module2'], function(m1, m2){ 使用m1/m2 })
AMD规范的典型实现是RequireJS,它是一个工具库,主要用于客户端的模块管理。通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。
//定义没有依赖的模块 define(function(require, exports, module){ exports.xxx = value module.exports = value }) //定义有依赖的模块 define(function(require, exports, module){ //引入依赖模块(同步) var module2 = require('./module2') //引入依赖模块(异步) require.async('./module3', function (m3) { }) //暴露模块 exports.xxx = value }) define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() })
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系、输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
基本语法: export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
/** 定义模块 math.js **/ var basicNum = 0; var add = function (a, b) { return a + b; }; export { basicNum, add }; /** 引用模块 **/ import { basicNum, add } from './math'; function test(ele) { ele.textContent = add(99 + basicNum); }
如上例所示,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
// export-default.js export default function () { console.log('foo'); } // import-default.js import customName from './export-default'; customName(); // 'foo'
模块默认输出, 其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
ES6 模块与 CommonJS 模块的差异 它们有两个重大差异:
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ps: RequireJs 和 Sea.js 的实现其输出也是一个值的拷贝
1. 前端模块化详解(完整版) 2. Module 的语法 3. Module 的加载实现 4.【前端工程化系列】简谈前端模块化开发与开发规范 5. 前端模块化开发 - haoxl - 博客园 6. 详解JavaScript模块化开发 - trigkit4 - SegmentFault 思否 7. 前端模块化:CommonJS,AMD,CMD,ES6 - 掘金 8. 浅谈前端模块化- 腾讯Web前端IMWeb 团队社区| blog | 团队博客 9. 前端工程之模块化- FEX 10. 前端模块化** - 谦行 - 博客园 11 前端模块化和组件化理解- Counting Stars - SegmentFault 思否 12. js模块化历程
The text was updated successfully, but these errors were encountered:
No branches or pull requests
1. 什么是模块化
模块化是将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并组合在一起。块(文件)的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
在没有模块化之前,前端将不同的功能封装到不同的全局函数中,如下:
那么带来的问题就是:
为了解决这个问题,出现了namespace模式,如下:
但是以上方法仍然存在问题: 数据不安全。例如,可以直接修改里面的data
为了解决这个问题,出现了IIFE(Immediately-invoked function expression 立即执行函数表达式)模式,如下:
由于module中的data没有暴露,所以是不可修改的,代码myModule.data只会在window.myModule这个对象上新增一个data的属性。
但是以上方法仍然存在一个问题,如果module模块需要依赖其他模块怎么办? 需要对IIFE进行增强,如下:
以上就是前端的模块化
2. 什么是模块化规范
IIFE增强版的模块化实际上已经实现了前端的模块化,它带来的好处包括
但是IIFE增强版的模块化带来了新的问题,比如:
为了解决这两个问题,出现了模块化规范,比如 CommonJS, AMD, ES6, CMD规范。
3. 模块化规范--CommonJS
基本语法:
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。例:
上面代码通过module.exports输出变量x和函数addX。
require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。这点与ES6模块化有重大差异(下文会介绍)
3. 模块化规范-- AMD
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
基本语法:
AMD规范的典型实现是RequireJS,它是一个工具库,主要用于客户端的模块管理。通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
4. 模块化规范-- CMD
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。
基本语法:
5. 模块化规范-- ES6
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系、输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
基本语法:
export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
如上例所示,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
模块默认输出, 其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
ES6 模块与 CommonJS 模块的差异
它们有两个重大差异:
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ps: RequireJs 和 Sea.js 的实现其输出也是一个值的拷贝
6.总结
参考自:
1. 前端模块化详解(完整版)
2. Module 的语法
3. Module 的加载实现
4.【前端工程化系列】简谈前端模块化开发与开发规范
5. 前端模块化开发 - haoxl - 博客园
6. 详解JavaScript模块化开发 - trigkit4 - SegmentFault 思否
7. 前端模块化:CommonJS,AMD,CMD,ES6 - 掘金
8. 浅谈前端模块化- 腾讯Web前端IMWeb 团队社区| blog | 团队博客
9. 前端工程之模块化- FEX
10. 前端模块化** - 谦行 - 博客园
11 前端模块化和组件化理解- Counting Stars - SegmentFault 思否
12. js模块化历程
The text was updated successfully, but these errors were encountered: