Blog
Blog copied to clipboard
作用域与闭包 - 了解模块化及其典型方案
了解模块化及其典型方案
模块化解决的问题
- 命名空间污染:如果变量都挂载在全局对象上,容易命名冲突,变量覆盖,也就是我们常说的“全局变量污染”;
- 维护性差:模块化将各部分功能分割开来,高内聚低耦合,提升代码的可维护性,降低维护成本;
- 复用性差:没有模块化时,复用全靠复制粘贴,模块化后,需要时只需引入相应依赖即可,一处定义、多处使用。
各模块化方案
ES Module
ES Module是ES6提出的模块化标准,属于编译时加载(静态加载),只能存在于顶层作用域。
动态import已通过提案,列入最新 ECMA标准 中。
/* ----- Export Syntax ---------- */
// default exports
export default 42
export default {}
export default []
export default (1 + 2)
export default foo
export default function () {}
export default class {}
export default function foo () {}
export default class foo {}
// variables exports
export var foo = 1
export var foo = function () {}
export var bar
export let foo = 2
export let bar
export const foo = 3
export function foo () {}
export class foo {}
// named exports
export {}
export {foo}
export {foo, bar}
export {foo as bar}
export {foo as default}
export {foo as default, bar}
// exports from
export * from 'foo'
export {} from 'foo'
export {foo} from 'foo'
export {foo, bar} from 'foo'
export {foo as bar} from 'foo'
export {foo as default} from 'foo'
export {foo as default, bar} from 'foo'
export {default} from 'foo'
export {default as foo} from 'foo'
/* ----- Import Syntax ---------- */
// default imports
import foo from 'foo'
import {default as foo} from 'foo'
// named imports
import {} from 'foo'
import {bar} from 'foo'
import {bar, baz} from 'foo'
import {bar as baz} from 'foo'
import {bar as baz, xyz} from 'foo'
// glob imports
import * as foo from 'foo'
// mixing imports
import foo, {baz as xyz} from 'foo'
import foo, * as bar from 'foo'
// just import
import 'foo'
CommonJS
常用于Node.js
中,属于运行时加载(动态加载)。
/* ----- Export Syntax ---------- */
// default exports
module.exports = function() {}
module.exports = {}
// named exports
exports.foo = function() {}
exports.bar = 1
exports.baz = class Baz {}
/* ----- Import Syntax ---------- */
// default imports
const foo = require('./foo')
// named imports
const { bar, baz } = require('./foo')
const { bar, baz: xyz } = require('./foo')
AMD & CMD
二者核心原理一致:解析模块依赖,通过插入script
标签的方式去加载依赖文件。
区别在于AMD推崇依赖前置,CMD推崇依赖就近,可结合下方示例代码理解,具体分析见 前端模块化之AMD与CMD原理。
// AMD
define(['./a','./b'], function (moduleA, moduleB) {
// 依赖前置
moduleA.mehodA();
console.log(moduleB.dataB);
// 导出数据
return {};
});
// CMD
define(function (requie, exports, module) {
// 依赖就近
var moduleA = require('./a');
moduleA.mehodA();
// 按需载入
if (needModuleB) {
var moduleB = requie('./b');
moduleB.methodB();
}
// 导出数据
exports = {};
});
IIFE + 闭包
刀耕火种的年代采用的方式,主要运用了闭包的特性,稍作了解即可。
var moduleA = (function ($, doc) {
var methodA = function() {};
var dataA = {};
return {
methodA: methodA,
dataA: dataA
};
})(jQuery, document);