Blog icon indicating copy to clipboard operation
Blog copied to clipboard

作用域与闭包 - 了解模块化及其典型方案

Open logan70 opened this issue 5 years ago • 0 comments

了解模块化及其典型方案

模块化解决的问题

  • 命名空间污染:如果变量都挂载在全局对象上,容易命名冲突,变量覆盖,也就是我们常说的“全局变量污染”;
  • 维护性差:模块化将各部分功能分割开来,高内聚低耦合,提升代码的可维护性,降低维护成本;
  • 复用性差:没有模块化时,复用全靠复制粘贴,模块化后,需要时只需引入相应依赖即可,一处定义、多处使用。

各模块化方案

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);

logan70 avatar Dec 03 '19 14:12 logan70