[转]非CMD模块的javascript文件兼容封装方案
本文转自:http://www.jackyrao.com/archives/383 | Jacky的博客
随着网站前台页面设计越来越花哨,其实现逻辑也越来越复杂。javascript库百花齐放,各种插件也层出不穷,在使用中,管理各种js文件依赖成为了一个令人头疼的问题。因此我们需要用软件工程的方式来编写javascript“程序”,即模块化编程。在制定中的ECMAScript第六版,也将引入模块这一概念。
目前常见的javascript模块规范有以RequireJS为代表的AMD规范和以SeaJS为代表的CMD规范,这两种都能达成浏览器端模块化开发的目的。
这几天我就在研究最近很火的支付宝大牛玉伯所写的SeaJS。
SeaJS为国人所写,因此中文文档看起来很爽。但不幸的是,很多著名的javascript框架和插件都不支持CMD规范,比如用得最多的jQuery和它的插件。如果想用它们进行模块化开发,就必须手动将他们封装成CMD模块。
对于jquery,一般这样封装:
define(function(){ jquery code.. return $.noConflict(true); });
封装后,jquery就成为标准CMD模块了,可以使用SeaJS的use方法或require方法直接读取:
seajs.use("jquery",function($){
$("p").css(......)
});
但是,这样封装以后存在隐患。比如某个新来的php程序员不懂这些,他可能像往常一样,引入<script src="jquery.js"></script>,然后$("p")调用,结果只会发现一行报错:$ is not a function。
因为jquery文件模块化以后,全局作用域已经不存在jquery或者$了,当然会报错。
所以我们需要一种兼容非模块化引用的封装方案 :
(function(factory) { if(typeof define === 'function'){ define(factory); }else{ factory(); } })(function(require){ jquery code.. if(require) return $.noConflict(true); });
原理看出来了吧,把一个匿名函数当做变量传入闭包,判断有无SeaJS提供的define方法。若有,则为CMD模块读取,返回$.noConflict(true);若无,则为普通的脚本引入,执行原生的jquery代码。
这样封装以后,就不怕程序员的误操作了。同理,其他的javascript文件也可以进行类似的封装。
======================很一般的分隔线=======================================
以上内容是原作者Jacky的原文,我想做一点点补充说明,那就是:
1、如果是要做传统的同步引用加载js文件,而且引用文件中有seajs或requirejs的话,那么一定要将用以上方法封装改造成后的JS文件放在seajs和requirej之前,因为seajs、requirejs中定义了define方法,如果改造过的JS文件放在seajs之后引用,永远会进行到if语句中,不会到else中,$方法会因没有暴露出来而无法使用;


2、类似下面的代码也是经常会出现在知名js框架工具中,也是用来做模块封装时的兼容性处理,贴出来只做参考及备用:
if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = Zepto; } exports.Zepto = Zepto; } else if (typeof define === 'function' && define.amd) { define(function () { return Zepto; }); } else { //window.Zepto = Zepto; }

浙公网安备 33010602011771号