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. 项目总结之HashMap问题

    在项目中我需要用另一个项目的中的方法,在另一个项目中的方法返回值是一个hashmap,返回的不是一个hashMap中存的对象而是Object对象.在一个项目中调用另一个项目中的方式是直接引入另一个项目 ...

  2. Java基础知识陷阱(二)

    本文发表于本人博客. 上次说了一些关于字符串的知识,都是比较基础的,那这次也说下关于对象地址问题,比如传参.先看下面代码: public void changeInt(int a){ a = ; } ...

  3. C# 使用 Windows API 发送文件到打印机

    最近需要做一个打印的功能,于是在网上找到了这么一个方法. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public cl ...

  4. 论文笔记:OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks

    2014 ICLR 纽约大学 LeCun团队 Pierre Sermanet, David Eigen, Xiang Zhang, Michael Mathieu, Rob Fergus, Yann ...

  5. QML学习之浅谈Window

     转载地址:http://blog.csdn.net/kanchuan1905/article/details/53762788 在Qt Quick的世界里,Window对象用于创建一个与操作系统相关 ...

  6. Linux Java环境搭建

    -------------------------网络配置-------------------------------1.配置DNS:vi /etc/resolv.confnameserver 19 ...

  7. 20145314郑凯杰 《Java程序设计》实验二 实验报告

    20145314郑凯杰 <Java程序设计>实验二 实验报告 实验要求 完成实验.撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用 ...

  8. 收藏 19 个 ES6常用的简写技巧

    代码精炼是每个有追求的程序所向往的,本文总结了19个JavaScript的简写技术,其中包括三元操作符.短路求值简写方式.声明变量简写方法等等,还有些自己的理解加上去:希望对你有帮助. 三元操作符 当 ...

  9. [Hdu6315]Naive Operations

    题意:给定一个初始数组b和一个初始值全部为0的数组a,每次操作可以在给定的区间(l,r)内让a[i](l=<i<=r)加一,或者查询区间区间(l,r)中a[i]/b[i](l=<i& ...

  10. eclipse不能添加tomcat7的问题

    问题如下: 解决问题: 1.把eclipse先关了 2.把eclipse的工作空间的两个文件删除 org.eclipse.jst.server.tomcat.core.prefs和org.eclips ...