在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等。
因此在复杂项目中引入AMD的概念,AMD:全称是Asynchronous Module Definition,即异步模块加载机制。通过AMD可以不需要在页面中手动添加<script>来引用脚本,而通过定义依赖自动加载模块脚本,接下来的代码将讲解如何实现建议的AMD模块,如果需要查看比较详细的实现可以下载requirejs源码。
简易实现整体思路:
1.将模块名及模块文件地址存入内存
2.通过define方法将模块名及模块依赖关系以及模块实现代码存入内存
3.require方法通过loadscript方法将需要依赖的模块代码导入并执行define方法存入内存,模块通过入参传入实际代码中,从而完成模块加载。
1.定义模块:
实现模块的定义,并将模块定义存储。
/** * * @param id 模块名 * @param deps 依赖模块 * @param factory 模块实现 */ define: function (id, deps, factory) {
在定义模块中,需要将模块名,模块依赖,模块代码存储至内存中
/** * * @param id 模块名 * @param deps 依赖模块 * @param factory 模块实现 */ define: function (id, deps, factory) { // 模块是否存在 if (modules[id]) throw new Error("module:" + id + "已经存在!"); if (arguments.length > 2) { modules[id] = { id: id, deps: deps, factory: factory } } else if (arguments.length == 2) { modules[id] = { id: id, factory: deps } } else { throw new Error("module:参数有误!"); } },
2.引用模块:
输入依赖模块名,执行代码,代码示例如下:
/** * 异步导入模块 * @param deps 依赖模块 * @param callback * @returns {{}} */ require: function (deps, callback) { // 插入脚本 deps = [].slice.call(deps); // 获取依赖脚本 loadScript(deps, buildModule, callback); },
详细步骤:
首先需要从依赖的文件夹中导入脚本,
/** * 从外部加载js * @param deps 依赖模块 * @param buildModule 创建模块方法 * @param callback */ function loadScript(deps, buildModule, callback) { var depJsCounter = 0; deps.forEach(function (dep) { var script = document.createElement("script") script.type = "text/javascript"; script.src = configs[dep]; document.getElementsByTagName("head")[0].appendChild(script); script.onload = function () { // 依赖js加载计数标记 depJsCounter++; if (depJsCounter == deps.length) { buildModule(deps, callback)(); } }; }); }
构建模块,从全局module中取出依赖模块,将依赖模块作为入参注入到现有模块,最后执行现有模块
/** * 创建模块 * @param deps 依赖模块 * @param callback * @returns {Function} */ var buildModule = function (deps, callback) { return function () { // 获取依赖模块 var args = []; deps = [].slice.call(deps); deps.forEach(function (dep) { var module = modules[dep] if (typeof module.factory === 'function') module.factory = module.factory(); args.push(module.factory) }) // 将依赖模块注入到callback中 var temp = {}; callback.apply(temp, args); return temp } }
3.注册模块
注册模块主要将名字与文件路径关联起来,便于从路径中下载js,代码清单如下:
/** * 注册模块 * @param obj */ config: function (obj) { var path = obj.paths; for (var el in path) { Object.defineProperty(configs, el, { enumerable: false, configurable: false, writable: true, value: path[el] }) } } }
4.执行实例
编写模块
define('module1', function () { var module1 = {}; module1.sayhello = function () { return 'hello module1'; } return module1; });
将代码保存js文件并取名module1
新建html文件,在html中先注册模块,通过require 导入模块,并利用模块编写代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="/demo/01Requirejs/require.js"></script> </head> <body> </body> </html> <script> require.config({ paths:{ module1:'/demo/01Requirejs/module1.js' } }); require(['module1'],function(module1){ alert(module1.sayhello()); }) </script>