zoukankan      html  css  js  c++  java
  • 一个简单的AMD模块加载器

    一个简单的AMD模块加载器

    参考
    https://github.com/JsAaron/NodeJs-Demo/tree/master/require
    PS Aaron大大的比我的完整

    PS
    这不是一个通用的模块加载器, 实际上只是require define 函数的实现
    所以每个模块的js都要引入到html文件中

    如何防止变量冲突呢?

    实际上就是用函数把他们包起来

    (function(exp){
      var mod = {
        name:'modA'
      };
      exp[mod.name] = mod;
    })(exp);
    

    exp是一个全局变量 保存所有的模块 然后require一个模块的时候实际上就是去exp这个全局变量中找

    AMD是如何使用模块的呢

    //定义一个模块
    define('a', function(){
      console.log('this is mod A');
      return {
        name: 'a'
      }
    });
    
    //调用一个模块
    require('a',function(a){
      console.log(a.name)
    })
    
    require('a', function(a){
      console.log(a.name + ' 2 ');
    })
    

    Step1

    
    var require; //两个全局量
    var define;
    (function() {
      var modules = {};
      require = function(id, callback) {
        if (!modules[id]) {
          throw "module " + id + " not found";
        }
        if (callback) {
          var module = build(modules[id]);
          callback(module)
          return module;
        }
      };
      define = function(id, factory) { //模块名,模块本身
        if (modules[id]) {
          throw "module " + id + " 模块已存在!";
        }
        modules[id] = {
          id: id,
          factory: factory
        };
      }
      //module {id: ''  factory: function(){...}}  //factory的function就是一个模块function中的内容
      function build(module) {
        var  factory = module.factory,
          id = module.id;
        module.exports = factory() || {};
        return module.exports; //模块return的结果
      }
    })();
    
    
    
    

    那么这样一来 上面require的执行结果是

    this is mod A
    a
    a.js:2 this is mod A
    a 2 
    

    模块确实是加载了 但是模块A执行了两次

    Step2

    那么凡是require过的模块 下次再次require 应该从保存的地方取出来而不是再次执行factory
    需要一个全局变量 pushStack = {} 来保存

      function build(module) {
        var  factory = module.factory,
          id = module.id;
        if(pushStack[id]){
          return pushStack[id];
        }
        module.exports = factory() || {};
        pushStack[id] = module.exports;
        return module.exports; //模块return的结果
      }
    

    Step3 require增加多依赖支持

    有了多依赖支持就可以这样做

    require(['a', 'b'], function(a,b){
      console.log(a.name);
      console.log(b.name);
    });
    

    改造require就可以了

      require = function(id, callback) {
        if(Object.prototype.toString.call(id) == '[object Array]'){
          var ids = id, allMod = {};
          ids.forEach(function(id){
            allMod[id] = build(modules[id]);
          });
          callback.apply(null, allMod);
        }else{
          if (!modules[id]) {
            throw "module " + id + " not found";
          }
          if (callback) {
            var module = build(modules[id]);
            callback(module)
            return module;
          }
        }
      };
    

    Step4

    有时候模块本身存在依赖 比如

    define('c',['a','b'],function(a,b){
    });
    
    

    那么define的时候就要对参数做判断 如果是三个参数表示是有依赖的模块

    var require; //两个全局量
    var define;
    (function() {
      var modules = {},pushStack = {};
    
      //require的时候才是真的执行模块 
      require = function(id, callback) {
        if(Object.prototype.toString.call(id) == '[object Array]'){
          var ids = id, allMods = [];
          ids.forEach(function(id){
            allMods.push(build(modules[id]));
          });
          callback.apply(null, allMods);
        }else{
          if (!modules[id]) {
            throw "module " + id + " not found";
          }
          if (callback) {
            var module = build(modules[id]);
            callback(module)
            return module;
          }
        }
      };
    
      //define的时候是把模块存放起来  存到modules[]中
      //define的参数 若是2个 那么是 模块名,模块本身, 若有三个参数 则是 模块名,依赖列表,模块本身
      define = function(id) {
        var deps, factory;
        if (modules[id]) {
          throw "module " + id + " 模块已存在!";
        }
        if(arguments.length > 2){
          deps = arguments[1];
          factory = arguments[2];
          modules[id] = {
            id: id,
            deps: deps,
            factory: factory
          };
        }else{
          factory = arguments[1];
          modules[id] = {
            id: id,
            factory: factory
          };
        }
      }
      function build(module) {
        var  factory = module.factory,
          id = module.id;
        if(pushStack[id]){
          return pushStack[id];
        }
        if(module.deps){
          var deps = [];
          module.deps.forEach(function(id){
            deps.push(build(modules[id]));
          });
          module.exports = factory.apply(null,deps);
        }else{
          module.exports = factory() || {};
        }
        pushStack[id] = module.exports;
        return module.exports; //模块return的结果
      }
    })();
    
    

    如何加入CMD支持

    完成上面,就可以通过下面的方式定义模块

    define('a',function(){
    });
    
    define('c',['a','b'],function(a,b){
    });
    
    require('a','b',function(a,b){}})
    
    

    在Seajs中CMD类似于这样

    define('c', function(require, exports, module) {
        var a = require('a')
        var b = require('b');
    });
    

    实际上就是改造require (require的时候才是执行模块的定义函数)
    require原本都是接受2个参数 依赖名以及一个函数 现在require可以只接受一个参数

    var require; //两个全局量
    var define;
    (function() {
      var modules = {},pushStack = {};
    
      //require的时候才是真的执行模块
      require = function(id, callback) {
        if(Object.prototype.toString.call(id) == '[object Array]'){
          var ids = id, allMods = [];
          ids.forEach(function(id){
            allMods.push(build(modules[id]));
          });
          callback.apply(null, allMods);
        }else{
          if (!modules[id]) {
            throw "module " + id + " not found";
          }
          if (callback) {
            var module = build(modules[id]);
            callback(module);
            return module;
          }else{
            return build(modules[id]);
          }
        }
      };
    
      //define的时候是把模块存放起来  存到modules[]中
      //define的参数 若是2个 那么是 模块名,模块本身, 若有三个参数 则是 模块名,依赖列表,模块本身
      define = function(id) {
        var deps, factory;
        if (modules[id]) {
          throw "module " + id + " 模块已存在!";
        }
        if(arguments.length > 2){
          deps = arguments[1];
          factory = arguments[2];
          modules[id] = {
            id: id,
            deps: deps,
            factory: factory
          };
        }else{
          factory = arguments[1];
          modules[id] = {
            id: id,
            factory: factory
          };
        }
      }
      function build(module) {
        var  factory = module.factory,
          id = module.id;
        if(pushStack[id]){
          return pushStack[id];
        }
        if(module.deps){
          var deps = [];
          module.deps.forEach(function(id){
            deps.push(build(modules[id]));
          });
          module.exports = factory.apply(module,deps);
        }else{
          module.exports = factory(require, module.exports, module) || {};
        }
        pushStack[id] = module.exports;
        return module.exports; //模块return的结果
      }
    })();
    
    

    之后就可以这样通过CMD的方式引入模块了

    define('c', function(require, exports, module) {
        var a = require('a');
        var b = require('b');
        return {
          name: 'c' + a.name + b.name
        }
    });
    
  • 相关阅读:
    js定时相关函数:
    远程控制使用kill软件映射内网进行远程控制(9.28 第十四天)
    PHP基础(9.27 第十三天)
    使用kali中的Metasploit通过windows7的永恒之蓝漏洞攻击并控制win7系统(9.27 第十三天)
    Nmap目录扫描和漏洞扫描(9.27 第十三天)
    JS正则和点击劫持代码(第十二天 9.27)
    Banner信息收集和美杜莎使用(9.26 第十二天)
    JavaScript的运算符、条件判断、循环、类型转换(9.25 第十一天)
    使用BurpSuite和Hydra爆破相关的服务(9.25 第十一天)
    JavaScript(第十一天 9.24)
  • 原文地址:https://www.cnblogs.com/cart55free99/p/4953611.html
Copyright © 2011-2022 走看看