js的模块模式被定义为给类提供私有和公共封装的一种方法,也就是我们常说的“模块化”。

    怎么实现“模块化”?

      通过闭包的原理来实现“模块化”  ,具体实现:1.必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例);2.封闭函数必须返回至少一个内部函数(返回多个函数时,以对象字面量的形式返回)

      先看一个实例:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function Module (){
         //内部变量
var something = 'cool';
var another = [1,2,3];
       //内部函数
function doSomething(){
console.log(something);
} function doAnother(){
console.log(another);
}
       //返回对象字面量形式,里面包含内部函数的引用, 这样就保持了内部变量是隐藏且私有的状态。
return {
doSomething: doSomething,
doAnother: doAnother
};
}
     //调用外部函数Module创建一个模块实例foo
var foo = Module();
foo.doSomething();//cool
foo.doAnother();//[1,2,3]
</script>
</body>
</html>

  简单分析一下代码:

      首先,Module只是一个函数,必须通过他才能创建一个模块实例,如果不执行他,内部作用域和闭包都无法被创建。 其次,Module函数返回一个字面量对象,这个返回的对象含有对内部函数而不是内部变量的引用。这样就保持了内部变量是隐藏且私有的状态。可以将这个对象类型的返回值看作模块的公共API 这个API最终会被赋值给外部的变量foo,通过他就可以访问API中的属性方法,比如:foo.doSomething()。

  上面的实例中,Module函数可以调用任意多次,每次调用都会创建一个新的模块实例。当只需要一个实例时,可以对这个模块进行简单的改进来实现单例模式:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var foo = (function Module (){
var something = 'cool';
var another = [1,2,3]; function doSomething(){
console.log(something);
} function doAnother(){
console.log(another);
} return {
doSomething: doSomething,
doAnother: doAnother
};
})(); foo.doSomething();//cool
foo.doAnother();//[1,2,3]
</script>
</body>
</html>

  通过将模块函数转换为IIFE(立即执行函数),立即调用这个函数并将返回值直接赋值给电力的模块实例foo

  模块也是普通的函数,因此可以接收参数:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// var foo = (function Module (){
// var something = 'cool';
// var another = [1,2,3]; // function doSomething(){
// console.log(something);
// } // function doAnother(){
// console.log(another);
// } // return {
// doSomething: doSomething,
// doAnother: doAnother
// };
// })(); // foo.doSomething();//cool
// foo.doAnother();//[1,2,3] var foo = (function Module(id){
function change(){
publicAPI.id = id2;
} function id1(){
console.log(id);
} function id2(){
console.log(id.toUpperCase());
} var publicAPI = {
change: change,
id: id1
}; return publicAPI;
})('hello'); foo.id();//hello
foo.change();
foo.id();//HELLO
</script>
</body>
</html>

  可以看出:通过在模块实例的内部保留公共API对象的内部引用(API指的是引用return回来的字面量对象 {...}),可以从内部模块实例进行修改,包括添加、删除方法和属性,以及修改它们的值。

  现代的模块机制

    大多数模块依赖加载器/管理器,本质上都是将模块定义为封装进一个API。 现在,宏观了解一下模块机制:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var myModule = (function Module(){
var modules = [];
       //定义一个define函数用于定义一个模块
function define(name, deps, impl){
for (var i = 0;i < deps.length;i++){
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl, deps);
} function get(name){
return modules[name];
} return {
define: define,
get: get
};
})();
</script>
</body>
</html>

  这段代码的核心就是:modules[name] = impl.apply(impl, deps)。 为了模块的定义(define函数)引入包装函数(可以传入任何依赖),并且将返回值,也就是模块的API,存储在一个根据名字来管理的模块列表中。(不是很理解啊??)

  下面展示了如何使用它来定义模块:

  

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var myModule = (function Module(){
var modules = []; function define(name, deps, impl){
for (var i = 0;i < deps.length;i++){
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl, deps);
} function get(name){
return modules[name];
} return {
define: define,
get: get
};
})(); myModule.define('bar', [], function(){
function hello(who){
return "Hello," + who;
}; return{
hello:hello
};
}); myModule.define('foo', ['bar'], function(bar){
var hungry = 'hippo'; function awesome(){
console.log(bar.hello(hungry).toUpperCase());
}; return {
awesome: awesome
};
}); var bar = myModule.get('bar');
var foo = myModule.get('foo'); console.log(bar.hello('hippo'));//hello, hippo
foo.awesome();//HELLO, HIPPO
</script>
</body>
</html>

  ‘foo’和‘bar’模块都是通过一个返回公共API的函数来定义的。‘foo’甚至接受‘bar’的实例作为依赖参数,并使用它。

    这就是模块的威力!!

  总结一下:模块并不是什么神秘的东西,他只是一个外部函数返回内部函数的引用(字面量对象的形式返回),从而可以访问内部函数和变量的一种方式。

                              ---摘自《你不知道的JavaScript》(上)   2017-3-22  23:24

JavaScript---js的模块化的更多相关文章

  1. JAVAScript:前端模块化开发

    目录 一:前端模块化概要 1.1.模块化概要 1.2.函数封装 1.3.对象封装 1.4.立即执行函数表达式(IIFE) 1.5.模块化规范 1.5.1.CommonJS 1.5.2.AMD((Asy ...

  2. JavaScript 中的模块化

    JavaScript 中的模块化 最早的基于立即执行函数,闭包的模块化 const MountClickModule = function(){  let num = 0;  const handle ...

  3. 简单聊一聊Javascript中的模块化

    在面试中只要说到模块化的问题,多多少少总会问到这些,umd.amd.cjs.esm,可能听过其中一个两个,或者都听说过.接下来我们先简单了解一下他们到底是什么,又有什么样的区别呢. 最开始的时候,Ja ...

  4. javascript(js)小数精度丢失的解决方案

    原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3* ...

  5. 【转】关于URL编码/javascript/js url 编码/url的三个js编码函数

    来源:http://www.cnblogs.com/huzi007/p/4174519.html 关于URL编码/javascript/js url 编码/url的三个js编码函数escape(),e ...

  6. paip.java 以及JavaScript (js) 的关系以及区别

    paip.java 以及JavaScript (js) 的关系以及区别 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http:// ...

  7. 关于URL编码/javascript/js url 编码/url的三个js编码函数

    关于URL编码/javascript/js url 编码/url的三个js编码函数escape(),encodeURI(),encodeURIComponent() 本文为您讲述关于js(javasc ...

  8. JavaScript js无间断滚动效果 scrollLeft方法 使用模板

    JavaScript js无间断滚动效果 scrollLeft方法 使用模板 <!DOCTYPE HTML><html><head><meta charset ...

  9. JavaScript(js)/上

    JavaScript(js) ECMA-----定义的基础语法 DOM------document  object  model BOM------Browser  object  model Jav ...

  10. 【HANA系列】SAP HANA XS使用JavaScript(JS)调用存储过程(Procedures)

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...

随机推荐

  1. 树莓派搭建Git服务器

    目录 安装ssh 安装git-core 新增git用户 设置git用户目录 [服务端]设置git仓库 [客户端]设置git仓库 设置ssh登录 安装ssh sudo apt-get install s ...

  2. PKU 2352 Stars(裸一维树状数组)

    题目大意:原题链接 就是求每个小星星左小角的星星的个数.坐标按照Y升序,Y相同X升序的顺序给出由于y轴已经排好序,可以按照x坐标建立一维树状数组 关键是要理解树状数组中的c[maxn]数组的构成方式, ...

  3. SHUOJ Arithmetic Sequence (FFT)

    链接:http://acmoj.shu.edu.cn/problem/533/ 题意:求一个序列中,有多少三元组(其中元素不重复)在任意的排列下能构成等差数列. 分析:等差数列:\(A_j-A_i=A ...

  4. javaWeb 使用线程池+队列解决"订单并发"问题

    解决方式:使用线程池+队列 项目基于Spring,如果不用spring需要自己把 ThreadPoolManager.java 改成单例模式 1.写一个Controller(Spring mvc) / ...

  5. STC51六中中断配置点亮一个LED

    一.外部中断0.1(分别點亮一個LED) /****************************************************************************** ...

  6. Android Studio开发学习 - 1. 添加Activity

    1. 项目上点右键,New -> Activity -> Blank Activity 这将生成Activity的 Layout.Class .和相关的配置信息(在AndroidManif ...

  7. POJ_1703 并查集应用

    通过这题基本完整理解了并查集的构建和使用.很轻巧的一种数据结构. 本题的方法值得注意:并没有直接构建两个帮派的集合,而是构建: 关系确认集合+若干单元素集(也即未确认帮派的初始状态)并辅助一个rel数 ...

  8. 爬虫之Xpath案例

    案例:使用XPath的爬虫 现在我们用XPath来做一个简单的爬虫,我们尝试爬取某个贴吧里的所有帖子,并且将该这个帖子里每个楼层发布的图片下载到本地. # tieba_xpath.py #!/usr/ ...

  9. Linux内核、 TCP/IP、Socket参数调优

    /proc/sys/net目录 所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sys/net目录下内容的修改都是临时的,任何修改在系统重启后都会丢失),例如下面这 ...

  10. cocos2d-x入门一

    为什么要学cocos2d-x        首先要明白什么是cocos2d-x,能干什么.cocos2d-x是一种跨平台的2D.3D游戏开发工具,目前较为流行的大多数android.ios游戏都是用它 ...