使用模块化编程库和闭包

In parahome on 2015-04-11 by para

1 问题及方案

后台js代码规范度不好,怎么写的都有,不易维护、复用度低,我们不期全部使用backbone做到前端MVC,但使用模块化编程库做到模块化开发还是简单而有意义的。

2 为什么要模块化

时至今日,把脚本放在页面的底部,已不再是最佳的解决方案,甚至事与愿违,转化为性能的毒药。出于种种的原因,我们几乎从不直接在页面上插入js脚本,而是使用第三方的加载器,比如seajs或者requirejs。加载模块的概念,如果你是后端开发工程师,更不会陌生。Java、Python、C# 等等语言,都有includeimport等功能。JavaScript 语言本身也有类似功能,但目前还处于草案阶段,需要等到ES6 标准得到主流浏览器支持后才能使用。 模块化编程是十分便捷的工程管理工具,简化了代码的结构,让文件的功能变得单一易维护复用度高。更重要的是管理了文件依赖和消除了命名冲突问题,并利用 AMD / CMD 规范统一了格式。如果工具提供了异步加载,还可以避免页面停止渲染被js阻塞。

参见Seajs的作者玉伯的一篇文章

3 为什么要闭包

Javascript的全局变量是魔鬼”。一种优雅的解决方式是闭包。配合var关键字,匿名函数可以实现有效隔离,不会造成全局变量的污染。闭包函数在不使用全局变量的情况下使变量得以保持,使父函数始终在内存中。使代码风格跟面向对象接近。把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value)(这时一定要小心,不要随便改变父函数内部变量的值)。注意:模块中如果不使用var定义变量,那么变量就是全局的。在入口、在其他模块都可以用。

4 Seajs

seajs定义了两个关键字define,require。前者定义一个模块,后者允许在模块中加载其他模块。 require 可以认为是 Sea.js 给 JavaScript 语言增加的一个 语法关键字,通过 require 可以在模块同步或者异步的获取其他模块通过 exports提供的接口(同时执行未包装的代码)。Sea.js 带来的两大好处:

  • 通过 exports 暴露接口。这意味着不需要命名空间了,更不需要全局变量。这是一种彻底的命名冲突解决方案。

  • 通过 require 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖,其他事情 Sea.js 都会自动处理好。对模块开发者来说,这是一种很好的 关注度分离,能让程序员更多地享受编码的乐趣

seajs所能加载的模块必须是按照CMD规范,用define定义的模块,但已经有一部分流行的函数库不是CMD规范的,比如jQuery。需要使用特殊的方式来加载。而且后台大部分的插件都是requirejs模块。对于非标准的模块加载,后者更有优势。

5 requirejs

requirejs是AMD规范的。同seajs一样有define和require两个关键字,不同的是,由于AMD即Asynchronous Module Definition,它的require就只有异步模式。seajs使用模块中的方法要通过exports关键字。而requirejs则直接使用define回调函数的返回获取可用的方法,同样是闭包。paths多次配置,跟seajs一样是取并集的。而且模块中不用var定义的变量都是全局可见的 。

总结

时至今日,webpack基本一统了前端打包编译构建的天下,而其require引入模块化的概念也已深入人心,因为其接近于Node端CMD的模块化方式,越来越多的开发者和项目负责人选择了统一,AMD的声音也渐渐弱了下去。然而前端好比天下江湖之远,纷争终于平息,然而其发展并不会止于此,安迪-格鲁夫说过,一个完备的程序世界的价值远大于其之前的讨论,争辩和分歧,然而如果没有后者的存在,前者出现的可能性也不会很大。所以,继续前进吧,前端开发者们~

 
comments powered by Disqus