js模块化编程总结
来源:互联网 发布:域名怎么接入阿里云 编辑:程序博客网 时间:2024/06/04 17:44
经常会听到关于js模块化的各种规范和类库,觉得还是有必要搞懂前端的一些知识生态,温故知新,特此整理。
CommonJS
nodejs采用的规范,其主要面向服务端。require命令第一次加载会执行整个脚本
,在内存
中生成一个对象。
// 主要属性{ id: '...', // 模块名 exports: {...}, // 该模块导出的接口 loaded: true, // 模块是否加载完毕}
后面再次执行require命令,就会到内存对象中的exports属性上取值,但是不会再次执行该模块
// math.jsexports.add = function(a, b) { return a + b}
var add = require('math')math.add(2, 3) // 5
由于CommonJS是同步加载
模块,对于服务器,所有模块都放在本地硬盘,等待模块加载时间就是很短的硬盘读取文件时间,但是对于浏览器,限制于代理或者网速,从服务器加载模块的时候,有时候很慢,甚至’假死’
所以浏览器端不适合
应用CommonJS规范
AMD
AMD全称’Asynchronous Module Definition’,即’异步模块定义’,顾名思义,采用异步
方式加载模块
这里的异步指的是不堵塞浏览器其他任务(dom构建,css渲染等),而加载内部是同步的,加载完模块后立即执行回调
AMD也采用require命令加载模块,但是不用于CommonJS,它要求两个参数:
require([module], callback)
将之前的例子改成AMD规范的方式:
require(['math'], function(math) { // 回调函数中参数对应数组中的成员(模块) math.add(2, 3)})
RequireJS模块加载器,使用的就是AMD规范。
在定义模块的时候,必须使用特定的define()函数来定义,如果一个模块不依赖其他模块,那么可以直接写在define()函数中
define(id?, dependencies?, factory)
id:模块的名字,如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字;
dependencies:模块的依赖,已被模块定义的模块标识的数组字面量。依赖参数是可选的,如果忽略此参数,它应该默认为 [“require”, “exports”, “module”]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。
factory:模块的工厂函数,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
假定现在有一个math.js文件,定义了一个math模块。那么,math.js书写方式如下:
// math.jsdefine(function() { var add = function(x, y) { return x + y } return { add: add }})
加载方法如下:
// main.jsrequire(['math'], function(math) { alert(math.add(1, 1))})
如果math模块还依赖其他模块,写法如下:
// math.jsdefine(['dependenceModule'], function(dependenceModule) { // ...})
当require()函数加载math模块的手,就会先加载dependenceModule模块,当有多个依赖时候,就将所有依赖都写在define()函数的第一个参数数组中,所以说AMD是依赖前置
的,不同于CMD的依赖就近
CMD
CMD推崇依赖就近,延迟执行。可以把你的依赖写进代码的任意一行,如下:
define(factory)
factory为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module.
// CMD
define(function(require, exports, module) { var a = require('./a') a.doSomething() var b = require('./b') b.doSomething()})
如果使用AMD写法,如下:
// AMDdefine(['a', 'b'], function(a, b) { a.doSomething() b.doSomething()})
这个规范实际上是为了Seajs的推广然后搞出来的。那么看看SeaJS是怎么回事儿吧,基本就是知道这个规范了。
同样Seajs也是预加载依赖js跟AMD的规范在预加载这一点上是相同的,明显不同的地方是调用,和声明依赖的地方。AMD和CMD都是用difine和require,但是CMD标准倾向于在使用过程中提出依赖,就是不管代码写到哪突然发现需要依赖另一个模块,那就在当前代码用require引入就可以了,规范会帮你搞定预加载,你随便写就可以了。但是AMD标准让你必须提前在头部依赖参数部分写好(没有写好? 倒回去写好咯)。这就是最明显的区别。
sea.js通过sea.use()来加载模块。
seajs.use(id, callback?)
UMD
虽然CommonJS和AMD的风格同样大受欢迎,但是看起来似乎它们并没有达成共识。这样的局面也导致了一种能同时支持两种风格的需要出现,这带给了我们通用模块定义。
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery', 'underscore'], factory) } else if (typeof exports === 'object') { // Node, CommonJS-like module.exports = factory(require('jquery'), require('underscore')) } else { // Browser globals (root is window) root.returnExports = factory(root.jQuery, root._) }}(this, function ($, _) { // methods function a(){} // private because it's not returned (see below) function b(){} // public because it's returned function c(){} // public because it's returned // exposed public methods return { b: b, c: c }}))
ES6
es6通过import、export实现模块的输入输出。其中import命令用于输入其他模块提供的功能,export命令用于规定模块的对外接口。
export
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果希望外部文件能够读取该模块的变量,就需要在这个模块内使用export关键字导出变量。如:
// profile.jsexport var a = 1export var b = 2export var c = 3
下面的写法是等价的,这种方式更加清晰(在底部一眼能看出导出了哪些变量):
var a = 1var b = 2var c = 3export {a, b, c}
export命令除了输出变量,还可以导出函数或类。
导出函数
export function foo(){}
function foo(){}function bar(){}export {foo, bar as bar2}
其中上面的as表示给导出的变量重命名。
要注意的是,export导出的变量只能位于文件的顶层,如果处于块级作用域内,会报错。如:
function foo() { export 'bar' // SyntaxError}
导出类
export default class {} // 关于default下面会说
export语句输出的值是动态绑定,绑定其所在的模块。
// foo.jsexport var foo = 'foo'setTimeout(function() { foo = 'foo2'}, 500)// main.jsimport * as m from './foo'console.log(m.foo) // foosetTimeout(() => console.log(m.foo), 500) // foo2
import
import命令可以导入其他模块通过export导出的部分。
// abc.jsvar a = 1var b = 2var c = 3export {a, b, c}//main.jsimport {a, b, c} from './abc'console.log(a, b, c)
如果想为导入的变量重新取一个名字,使用as关键字(也可以在导出中使用)。
import {a as aa, b, c}console.log(aa, b, c)
如果想在一个模块中先输入后输出一个模块,import语句可以和export语句写在一起。
import {a, b, c} form './abc'export {a, b, c}// 使用连写, 可读性不好,不建议export {a, b, c} from './abc'
模块的整体加载
使用*关键字。
// abc.jsexport var a = 1export var b = 2export var c = 3// main.jsimport * as abc form './abc'console.log(abc.a, abc.b, abc.c)
export default
在export输出内容时,如果同时输出多个变量,需要使用大括号{},同时导入也需要大括号。使用export defalut输出时,不需要大括号,而输入(import)export default输出的变量时,不需要大括号。
// abc.jsvar a = 1, b = 2, c = 3export {a, b}export default c
import {a, b} from './abc'import c from './abc' // 不需要大括号console.log(a, b, c) // 1 2 3
本质上,export default输出的是一个叫做default的变量或方法,输入这个default变量时不需要大括号。
// abc.jsexport {a as default}// main.jsimport a from './abc' // 这样也是可以的// 这样也是可以的import {default as aa} from './abc'console.log(aa)
- JS模块化编程总结
- js模块化编程总结
- Js 模块化编程
- JS模块化编程
- JS模块化编程
- JS模块化编程
- js模块化编程
- js模块化编程
- JS模块化编程
- js模块化编程
- JS模块化编程
- js模块化编程
- js模块化编程
- js模块化编程
- js的模块化编程
- C模块化编程总结
- js模块化编程 : require.js
- JS模块化编程 Require.JS
- 用面向对象解决 输入用户名自动显示邮箱后缀列表的方法
- 快速 排序的思想并实现一个快排?
- 分布式框架-Dubbox介绍
- 思辨人工智能 IBM Watson在帮每个人实现无限可能
- 14.ProcessBar进度条的应用实例:模拟两个进度条加载
- js模块化编程总结
- fake-useragent User Agent 伪装
- 基于Agile Lite开发框架实现底部导航切换页面
- 关于mysql字符串与时间戳
- 一道奥数题的简单实现
- struts2-convention-plugin-2.3.1.2.jar
- PHP平铺水印
- css自定义遮罩滑动
- MySQL数据库默认编码查看/修改