关于JS模块化的知识点分享

模块化是一个语言膨胀的必经之路,它能够帮助开发者拆分和组织代码。

Module模式

在模块化规范形成之前,JS开发者使用Module设计模式来解决JS全局作用域的污染问题。Module模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法。在JavaScript中,Module模式使用匿名函数自调用 (闭包)来封装,通过自定义暴露行为来区分私有成员和公有成员。

let myModule = (function (window) {
  let moduleName = 'module' // private
  // public
  function setModuleName(name) {
   moduleName = name
  }
  // public
  function getModuleName() {
   return moduleName
  }
  return { setModuleName, getModuleName } // 暴露行为
 })(window)

上面例子是Module模式的一种写法,它通过闭包的特性打开了一个新的作用域,缓解了全局作用域命名冲突和安全性的问题。但是,开发者并不能够用它来组织和拆分代码,于是乎便出现了以此为基石的模块化规范。

模块化规化

1. CommonJS

CommonJS主要用在Node开发上,每个文件就是一个模块,没个文件都有自己的一个作用域。通过module.exports暴露public成员。例如:

// 文件名:x.js
let x = 1;
function add() {
 x += 1;
 return x;
}
module.exports.x = x;
module.exports.add = add;

此外,CommonJS通过require()引入模块依赖,require函数可以引入Node的内置模块、自定义模块和npm等第三方模块。

// 文件名:main.js
let xm = require('./x.js');
console.log(xm.x); // 1
console.log(xm.add()); // 2
console.log(xm.x);  // 1

从上面代码我们可以看出,require函数同步加载了x.js,并且返回了module.exports输出字面量的拷贝值。可能有人会问module.exports.x = x;不是赋值吗,怎么肥事呢?我们说,Module模式是模块化规范的基石,CommonJS也是对Module模式的一种封装。我们完全可以用Module模式来实现上面的代码效果:

let xModule = (function (){
 let x = 1;
 function add() {
  x += 1;
  return x;
 }
 return { x, add };
})();
let xm = xModule;
console.log(xm.x); // 1
console.log(xm.add()); // 2
console.log(xm.x);  // 1

通过Module模式模拟的CommonJS原理,我们就可以很好的解释CommonJS的特性了。因为CommonJS需要通过赋值的方式来获取匿名函数自调用的返回值,所以require函数在加载模块是同步的。然而CommonJS模块的加载机制局限了CommonJS在客户端上的使用,因为通过HTTP同步加载CommonJS模块是非常耗时的。

2. AMD和CMD

2.1 AMD

// 定义AMD规范的模块
define([function() {
 return 模块
})

区别于CommonJS,AMD规范的被依赖模块是异步加载的,而定义的模块是被当作回调函数来执行的,依赖于require.js模块管理工具库。当然,AMD规范不是采用匿名函数自调用的方式来封装,我们依然可以利用闭包的原理来实现模块的私有成员和公有成员:

define(['module1', 'module2'], function(m1, m2) {
 let x = 1;
 function add() {
  x += 1;
  return x;
 }
 return { add };
})

2.2 CMD

CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。AMD 推崇依赖前置,CMD 推崇依赖就近。

define(function(require, exports, module) {
 // 同步加载模块
 var a = require('./a');
 a.doSomething();
 // 异步加载一个模块,在加载完成时,执行回调
 require.async(['./b'], function(b) {
  b.doSomething();
 });
 // 对外暴露成员
 exports.doSomething = function() {};
});
// 使用模块
seajs.use('path');

CMD集成了CommonJS和AMD的的特点,支持同步和异步加载模块。CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。因此,在CMD中require函数同步加载模块时没有HTTP请求过程。

ES6 module

ES6的模块化已经不是规范了,而是JS语言的特性。随着ES6的推出,AMD和CMD也随之成为了历史。ES6模块与模块化规范相比,有两大特点:

  • 模块化规范输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • 模块化规范是运行时加载,ES6 模块是编译时输出接口。

模块化规范输出的是一个对象,该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,ES6 module 是一个多对象输出,多对象加载的模型。从原理上来说,模块化规范是匿名函数自调用的封装,而ES6 module则是用匿名函数自调用去调用输出的成员。两者的区别可参考Babel and CommonJS modules。

以上就是本次介绍的全部知识点内容,感谢大家的学习和对我们的支持。

(0)

相关推荐

  • javascript 构建模块化开发过程解析

    在使用 sea.js .require.js . angular 的时候. 我们使用到 define . module(require) 的方式,定义模块,和依赖模块 下面给出 define 和 module 的简单实现. 其本质,就是往一个对象上面添加方法 var F = {}; F.define = function(str,fn){ var parts = str.split("."); var parent = this; // parent 当前模块的父模块 var i =

  • 详解Js中的模块化是如何实现的

    由于 Js 起初定位的原因(刚开始没想到会应用在过于复杂的场景),所以它本身并没有提供模块系统,随着应用的复杂化,模块化成为了一个必须解决的问题.本着菲麦深入原理的原则,很有必要来揭开模块化的面纱 一.模块化需要解决的问题 要对一个东西进行深入的剖析,有必要带着目的去看.模块化所要解决的问题可以用一句话概括 在没有全局污染的情况下,更好的组织项目代码 举一个简单的栗子,我们现在有如下的代码: function doSomething () { const a = 10; const b = 11

  • 详谈js模块化规范

    1. CommonJS 用于服务端模块化编程,比如nodejs就采用此规范: 一个文件就是一个模块,require方法用来加载模块,该方法读取一个文件并执行,最后返回文件内部的module.exports对象: require是默认读取.js文件的,所以require(模块名)可以不写后缀: 同步加载,由于服务端加载的模块一般在本地,所以可以这样:但是在客户器端如果一个模块过大就会导致页面"假死": module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上

  • 关于JS模块化的知识点分享

    模块化是一个语言膨胀的必经之路,它能够帮助开发者拆分和组织代码. Module模式 在模块化规范形成之前,JS开发者使用Module设计模式来解决JS全局作用域的污染问题.Module模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法.在JavaScript中,Module模式使用匿名函数自调用 (闭包)来封装,通过自定义暴露行为来区分私有成员和公有成员. let myModule = (function (window) { let moduleName = 'module' /

  • JS运动相关知识点小结(附弹性运动示例)

    本文总结了JS运动相关知识点.分享给大家供大家参考,具体如下: 1.多物体运动框架所有东西都不能共用 2.document.title输出频率不能太高 3.在写JS时尽量避免写小数,因为计算机内部都是模拟的,而不是实际存储的 如:0.07*100 在JS运算里不是为7 var a=3; var b=3.00000000000000000001; alert(a=b); 输出的结果却是true 4.写程序思考时先思考一般,再思考特殊,写程序是,先排除特殊,然后写一般 if(特殊1) {} else

  • JS运动框架之分享侧边栏动画实例

    本文实例讲述了JS运动框架之分享侧边栏动画实现方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <!DOCTYPE html>  <html>      <head>          <meta charset="utf-8">          <title></title>          <style type="text/css">         

  • js严格模式总结(分享)

    首页,我们要理解严格模式的概念,严格模式是一种特殊的执行模式,它修复了部分语言上的不足,提供更强的错误检查,病增强安全性.可以对部分函数进行执行严格模式,如: function func(){ 'use strict' } 也可以对整个js文件进行执行严格模式,如: 'use strict' function func(){ } 那么我们在以下情况不能使用: 1.不允许用width 2.不允许未声明的变量被赋值 3.arguments变为参数的静态副本 4.delete参数.函数名报错 5.de

  • 第二次聊一聊JS require.js模块化工具的基础知识

    前一篇:JS模块化工具我们以非常简单的方式引入了requirejs:http://www.jb51.net/article/82527.htm,这一篇将讲述一下requirejs中的一些基本知识,包括API使用方式等 基本API require会定义三个变量:define,require,requirejs,其中require === requirejs,一般使用require更简短 define 从名字就可以看出这个api是用来定义一个模块 require 加载依赖模块,并执行加载完后的回调函

  • 第一次接触JS require.js模块化工具

    随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求. RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的RequireJS压缩后只有14K,堪称非常轻量.它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升. requirejs能带来什么好处 官方对requ

  • js断点调试心得分享(必看篇)

    1.断点调试是啥?难不难? 断点调试其实并不是多么复杂的一件事,简单的理解无外呼就是打开浏览器,打开sources找到js文件,在行号上点一下罢了.操作起来似乎很简单,其实很多人纠结的是,是在哪里打断点?(我们先看一个断点截图,以chrome浏览器的断点为例) 步骤记住没? 用chrome浏览器打开页面 → 按f12打开开发者工具 → 打开Sources → 打开你要调试的js代码文件 → 在行号上单击一下,OK!恭喜你的处女断点打上了,哈哈~~ 2.断点怎么打才合适? 打断点操作很简单,核心的

  • JS严格模式知识点总结

    所谓严格模式其实就是一个不会赋值给任何变量的字符串 "use strict" 如果在全局作用域下 给出这个提示,那整个脚本将采用严格模式.也可以只在函数中打开严格模式 1.严格模式下没有全局变量 a="test" 严格模式下会报错,非严格模式下正常 2.删除变量 var 有三种声明的情形 var 声明的全局变量 var 声明的局部变量 eval()中声明的全局变量 第一种和第二种情况是无法用 delete删掉的. 首先第一种情况声明的全局对象虽然是windows的属

  • 详解Js模块化的作用原理和方案

    一.模块化概念 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起:块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信. 二.模块化作用 为什么要用模块化的JavaScript? 因为在实际的开发过程中,经常会遇到变量.函数.对象等名字的冲突,这样就容易造成冲突,还会造成全局变量被污染: 同时,程序复杂时需要写很多代码,而且还要引入很多类库,这样稍微不注意就容易造成文件依赖混乱: 为了解决上面的的问题,我们才开始使用模块化的js,所以说模块

随机推荐