一. 开发中遇到的问题
通常我们在做项目的时候一般会出现这样的一种情况。
<script> // a.js var varity=1; function changeHTML(){ //define function changeHTML } function decodeHTML(){ // define function decodeHTML } //……………… </script>
main.html的引入
<html> <body></body> <script src="a.js"></script> </html>
这个按照我们正常的写法上面来说是没有什么问题的,至少在使用上面没有问题,但是却存在一些隐患
1. 假设后来有A同事需要添加一个方法叫做decodeString来处理string文本,B同事如果也要添加一个类似的方法,那么就不能够使用decodeString来命名,除此之外这样的函数定义也会直接把函数暴露到全局中。
2. 变量也会被散乱分布到全局变量中,后续变量命名就会有命名冲突的隐患
3. 如果是函数与函数之间的依赖关系比较难维护等问题
二、初级的解决方案
对于这样的一种情况最开始谷歌的YUI提出的解决方案是与PHP,JAVA的解决方案相似就是添加一个命名空间。
上面的代码我们可以这样的去编写。
<script> // a.js // 变量 var variable={};//全局中只有唯一的一个variable,用来保存所有的变量 variable.varity=1; // 方法 var methods={};//全局中只有唯一的一个methods,用来保存所有的方法
var methods.common={}; methods.common.changeHTML=function(){ //define function changeHTML
alert(1);
} methods.common.decodeHTML = function () { //define function decodeHTML } </script>
我们发现这样的基本上面的这种方法是可以解决一些不必要的冲突的(除非你是想给自己挖坑),假如我们要添加一个关于用户登录的方法,我们可以这样写。
methods.users = {}; methods.users.login=function(str){ console.log(str); } methods.users.login("this is a test");
这样去管理方法和变量虽然相比于第一种方法来说可以有效的解决冲突,但是也是存在如下的一些问题:
1. 如果我们要调用这个简单的login方法,我们会发现需要书写一大串的前缀(methods.users.login)。代码编写风格不简洁
2. 变量虽然是可以有效的管理,但是确实没有解决读写的控制,特别是如果团队的人较多的话,容易发生误操作,所以应该进行读写分离。
三、进一步的解决方案
变量的管理方案----闭包
其实上面对变量的管理已经比较有效了,但只是缺少读写的控制,容易发生误操作,所以参照ES6的做法,重新编写了一个getter方法和setting方法来获取参数。
var val=function(){ var that=this; var variable={}; variable.varity=1; var returnVal={}; this.isString=function(str){ try { if (typeof str !== "string") { throw "TypeErr"; }else{ return true; } } catch (e) { if (e == "TypeErr") { return false; } } } returnVal.getter=function(str){ var isStr=that.isString(str); if(isStr){ return variable[str]; }else{ console.error("input type must string!!!!!"); } } returnVal.setter=function(key,value){ var isStr=that.isString(key); if(isStr){ if(variable[key]==undefined){ eval(variable[key]); } variable[key]=value; }else{ console.error("input type must string!!!!!"); } } return returnVal; }
运行代码测试:
var val= val();//初始化方法 console.log(val.getter("varity"));// 1 val.setter("va222rity",3);//不存在重新添加并赋值 console.log(val.getter("va222rity")); // 3
现在这样写变量就不容易发生误操作了(读写已经分离),也不会把变量泄漏到全局中去。
上面的函数就是对闭包的一个实际的应用。具体不懂的可以自行百度闭包的知识(具体还可以实现的更加的简洁,在这里不累赘)。
变量相关的优化方案我们已经说了,我们接下来说一说关于函数模块化的应用。
函数的管理方案-------模块化
模块化最早是由node.js提出来的一种规范,具体的实现是CommonJS
但是由于服务器端与浏览器端的不同,不同之处主要表现在服务器端加载文件是通过缓存读取本地文件的形式来实现的,所以加载的时间可以忽略不计,但是在浏览器端(前端)却不是这样的,每个文件都是通过HTTP请求从服务器中下载而来,所以中间会产生一定的加载时间,所以浏览器端和服务器端你是不同的。
服务器端
采用的方式是按需加载,也就是说什么时候需要就什么时候加载这个文件进来
浏览器端
共同点:都是实行对代码的预先加载
异同点:RequireJS提出的观点是预先加载并执行[早期],SeaJS提出的观点是预先加载,按需执行。
相比之下,作者更倾向于RequireJS的实现方式,具体原因如下
1.RequireJS社区和文档的支持比较完善
2,SeaJS项目停止维护
3.RequireJS在后续的版本中含括了SeaJS的功能
在实际的应用之中,一般模块化是用来解决以下的几种情况的:
1. 解决文件与文件之间相互的依赖关系所产生的问题,方便后期代码的升级维护。
2. 解决过渡加载不需要的函数代码
3. 函数直接不会泄漏到全局
具体的用法不过多的解释不懂点这里:http://www.zhangxinxu.com/sp/seajs/docs/zh-cn/module-definition.html#define
四、小结
写这篇文章的时候已经是2018年了,这些东西虽然可以用,但是未免有些过时。
该文章主要是讲关于闭包和模块化在项目中要怎样的合理使用,目前模块化最好的解决方案我认为是ES6的module。
但是考虑到团队中可能水平参差不齐,导致ES6推动的难度。所以建议首选ES6,次选RequireJS。
关于ES6的讲解介绍会在之后的文章提及,如果觉得文章对你有帮助请点个赞。