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. Pyspark访问Hbase

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl/p/7347167.html 转载请注明出处 记录自己最近抽空折腾虚拟机环境时用spark2.0的pyspark ...

  2. java中元注解

    java中元注解有四个: @Retention @Target @Document @Inherited:  @Retention:注解的保留位置 @Retention(RetentionPolicy ...

  3. python3_unittest单元测试框架

    看见英文懵逼,强迫学习英语 The Unittest suppots test automation,sharing of setup and shutdown code of tests, aggr ...

  4. 软件测试技术作业3---PrintPrimes()

    一.代码部分: private static void printPrimes (int n) { int curPrime; // Value currently considered for pr ...

  5. 5309 《Java程序设计》第6周学习总结

    教材学习内容总结 输入与输出 InputStream与OutputStream 从应用程序角度来看,如果要将数据从来源取出,可以使用输入串流:如果要将数据写入目的地,可以使用输出串流.在Java中,输 ...

  6. 20145230熊佳炜《网络对抗》实验八:WEB基础

    20145230熊佳炜<网络对抗>实验八:WEB基础 实验目标 Web前端HTML:能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTM ...

  7. windows 下获取父进程pid

    DWORD GetParentProcessID(DWORD dwProcessId) { LONG status; DWORD dwParentPID = (DWORD)-1; HANDLE hPr ...

  8. Vim 基本設置 – 使用Vim-plug管理插件 (3)【转】

    本文转载自:https://staryoru.github.io/vim-plugin-manager/ Vim中有很多非常好用的插件(plugin),對於這些插件的安裝.更新與移除等等,使用一個插件 ...

  9. 【网络结构】GoogLeNet inception-v1:Going deeper with convolutions论文笔记

    目录 0. 论文链接 1. 概述 2. inception 3. GoogleNet 参考链接 @ 0. 论文链接 1. 概述   GoogLeNet是谷歌团队提出的一种大体保持计算资源不变的前提下, ...

  10. Springboot依赖注入笔记

    结合Autowired和Service注解 public interface IUser { void say(); } @Service public class Student implement ...