关于前端模块化,玉伯在其博文 前端模块化开发的价值 中有论述,有兴趣的同学可以去阅读一下。

1. 模块加载器

模块加载器目前比较流行的有 Requirejs 和 Seajs。前者遵循 AMD规范,后者遵循 CMD规范。前者的规范产出比较适合于浏览器异步环境的习惯,后者的规范产出对于写过 nodejs 的同学来说是比较爽的。关于两者的比较,有兴趣的同学请参看玉伯在知乎的回答 AMD和CMD的区别有哪些。本文希望能按照 AMD 规范来简单实现自己的一个模块加载器,以此来搞清楚模块加载器的工作原理。

2. AMD规范与接口定义

在实现之前,我们需要拟定实现的API,然后才能进行下一步的编码。出于学习的目的,并没有完全实现 AMD规范 中定义的内容,简单实现的API如下:

 // 定义模块
 define(id?, dependencies?, factory);

 // 调用模块
 require(dependencies?, factory);

 // 模块加载器配置
 require.config({
     paths: {},
     shim: {
         'xx': {
             deps: [],
             exports: ''
         }
     }

 });

 // 模块加载器标识
 define.amd = {};

假如我们有以下的开发目录:

     scripts
         |-- a.js
         |-- b.js
         |-- c.js
         |-- d.js
         |-- main.js
     define.js
     index.html

除了 define.js 为需要实现的内容,各个文件的大概内容为:

 // a.js
 define(['b'], function(b) {

     return {
         say: function() {
             return 'a call: ' + b;
         }
     };

 });

 // b.js
 define(function() {
     return 'this is b';
 });    

 // c.js
 (function(global) {
     global.NotAmd = function() {
         return 'c, not amd module';
     }
 })(window);

 // d.js
 define(['b'], function(b) {

     return {
         say: function() {
             return 'd call: ' + b;
         }
     };

 });

 // main.js
 require.config({
     paths: {
         'notAmd': './c'
     },
     shim: {
         'notAmd': {
             exports: 'NotAmd'
         }
     }
 });

 require(['a', 'notAmd', 'd'], function(a, notAmd, d) {
     console.log(a.say());           // should be: a call: this is b
     console.log(notAmd());       // should be: c, not amd module
     console.log(d.say());           // should be: d call: this is b
 });

 // index.html
 <script src="vendors/define.js" data-main="scripts/main"></script>

上面的代码完全兼容于 Requirejs,将 define.js 换成 Requirejs,上面的代码就能成功跑起来。这里我们需要实现 define.js 来达到同样的效果。

3. 实现

一个文件对于一个模块。先看一下模块加载器的主要执行流程:

整个流程其实就是加载主模块(data-main指定的模块,里面有require调用),然后加载require的依赖模块,当所有的模块及其依赖模块都已加载完毕,执行require调用中的factory方法。

在实现过程中需要考虑到的点有:

1. 构造一个对象,用以保存模块的标识、依赖、工厂方法等信息。

2. 非AMD模块的支持。非AMD模块不会调用define方法来定义自己,如果不支持非AMD模块,那么该模块在加载完毕之后流程会中断,其exports的结果也不对。

3. 采用url来作为模块标识,由于url的唯一性,不同目录同id的模块就不会相互覆盖。

4. 循环依赖。可分为两种依赖方式:

 // 弱依赖:不在factory中直接执行依赖模块的方法
 // a.js
 define(['b'], function(b) {
     return {
         say: function() {
             b.say();
         }
     }
 });

 // b.js
 define(['a'], function(a) {
     return {
         say: function(a) {
             a.say();
         }
     }
 });

 // 强依赖:直接在factory中执行依赖模块的方法
 // a.js
 define(['b'], function(b) {
     b.say();

     return {
          say: function() {
              return 'this is a';
          }
      }
 });

 // b.js
 define(['a'], function(a) {
     a.say();

     return {
         say: function() {
             return 'this is b';
         }
     }
 });

对于弱依赖,程序的解决方式是首先传递undefined作为其中一个依赖模块的exports结果,当该依赖模块的factory成功执行后,其就能返回正确的exports值。对于强依赖,程序会异常。但是如果确实在应用中发生了强依赖,我们可以用另外一种方式去解决,那就是模块加载器会传递该模块的exports参数给factory,factory直接将方法挂载在exports上。其实这也相当于将其转换为了弱依赖。不过大部分情况下,程序里面发生了循环依赖,往往是我们的设计出现了问题。

好了,下面是 define.js 实现的代码:

 /*jslint regexp: true, nomen: true, sloppy: true */
 /*global window, navigator, document, setTimeout, opera */
 (function(global, undefined) {
     var document = global.document,
         head = document.head || document.getElementsByTagName('head')[0] || document.documentElement,
         baseElement = document.getElementsByTagName('base')[0],
         noop = function(){},
         currentlyAddingScript, interactiveScript, anonymousMeta,
         dirnameReg = /[^?#]*\//,
         dotReg = /\/\.\//g,
         doubleDotReg = /\/[^/]+\/\.\.\//,
         multiSlashReg = /([^:/])\/+\//g,
         ignorePartReg = /[?#].*$/,
         suffixReg = /\.js$/,

         seed = {
             // 缓存模块
             modules: {},
             config: {
                 baseUrl: '',
                 charset: '',
                 paths: {},
                 shim: {},
                 urlArgs: ''
             }
         };

     /* utils */
     function isType(type) {
         return function(obj) {
             return {}.toString.call(obj) === '[object ' + type + ']';
         }
     }

     var isFunction = isType('Function');
     var isString = isType('String');
     var isArray = isType('Array');

     function hasProp(obj, prop) {
         return Object.prototype.hasOwnProperty.call(obj, prop);
     }

     /**
      * 遍历数组,回调返回 true 时终止遍历
      */
     function each(arr, callback) {
         var i, len;

         if (isArray(arr)) {
             for (i = 0, len = arr.length; i < len; i++) {
                 if (callback(arr[i], i, arr)) {
                     break;
                 }
             }
         }
     }

     /**
      * 反向遍历数组,回调返回 true 时终止遍历
      */
     function eachReverse(arr, callback) {
         var i;

         if (isArray(arr)) {
             for (i = arr.length - 1; i >= 0; i--) {
                 if (callback(arr[i], i, arr)) {
                     break;
                 }
             }
         }
     }

     /**
      * 遍历对象,回调返回 true 时终止遍历
      */
     function eachProp(obj, callback) {
         var prop;
         for (prop in obj) {
             if (hasProp(obj, prop)) {
                 if (callback(obj[prop], prop)) {
                     break;
                 }
             }
         }
     }

     /**
      * 判断是否为一个空白对象
      */
     function isPlainObject(obj) {
         var isPlain = true;

         eachProp(obj, function() {
             isPlain = false;
             return true;
         });

         return isPlain;
     }

     /**
      * 复制源对象的属性到目标对象中
      */
     function mixin(target, source) {
         if (source) {
             eachProp(source, function(value, prop) {
                 target[prop] = value;
             });
         }
         return target;
     }

     function makeError(name, msg) {
         throw new Error(name + ":" + msg);
     }

     /**
      * 获取全局变量值。允许格式:a.b.c
      */
     function getGlobal(value) {
         if (!value) {
             return value;
         }
         var g = global;
         each(value.split('.'), function(part) {
             g = g[part];
         });
         return g;
     }

     /* path */
     /**
      * 获取path对应的目录部分
      *
      * a/b/c.js?foo=1#d/e  --> a/b/
      */
     function dirname(path) {
         var m = path.match(dirnameReg);

         return m ? m[0] : "./";
     }

     /**
      * 规范化path
      *
      * http://test.com/a//./b/../c  -->  "http://test.com/a/c"
      */
     function realpath(path) {
         // /a/b/./c/./d --> /a/b/c/d
         path = path.replace(dotReg, "/");

         // a//b/c --> a/b/c
         // a///b////c --> a/b/c
         path = path.replace(multiSlashReg, "$1/");

         // a/b/c/../../d --> a/b/../d --> a/d
         while (path.match(doubleDotReg)) {
             path = path.replace(doubleDotReg, "/");
         }

         return path;
     }

     /**
      * 将模块id解析为对应的url
      *
      * rules:
      * baseUrl: http://gcfeng.github.io/blog/js
      * host: http://gcfeng.github.io/blog
      *
      * http://gcfeng.github.io/blog/js/test.js  -->  http://gcfeng.github.io/blog/js/test.js
      *                                    test  -->  http://gcfeng.github.io/blog/js/test.js
      *                              ../test.js  -->  http://gcfeng.github.io/blog/test.js
      *                                /test.js  -->  http://gcfeng.github.io/blog/test.js
      *                            test?foo#bar  -->  http://gcfeng.github.io/blog/test.js
      *
      * @param {String} id 模块id
      * @param {String} baseUrl 模块url对应的基地址
      */
     function id2Url(id, baseUrl) {
         var config = seed.config;

         id = config.paths[id] || id;

         // main///test?foo#bar  -->  main/test?foo#bar
         id = realpath(id);

         // main/test?foo#bar  -->  main/test
         id = id.replace(ignorePartReg, "");

         id = suffixReg.test(id) ? id : (id + '.js');

         id = realpath(dirname(baseUrl) + id);

         id = id + (config.urlArgs || "");

         return id;
     }

     function getScripts() {
         return document.getElementsByTagName('script');
     }

     /**
      * 获取当前正在运行的脚本
      */
     function getCurrentScript() {
         if (currentlyAddingScript) {
             return currentlyAddingScript;
         }

         if (interactiveScript && interactiveScript.readyState === 'interactive') {
             return interactiveScript;
         }

         if (document.currentScript) {
             return interactiveScript = document.currentScript;
         }

         eachReverse(getScripts(), function (script) {
             if (script.readyState === 'interactive') {
                 return (interactiveScript = script);
             }
         });
         return interactiveScript;
     }

     /**
      * 请求JavaScript文件
      */
     function loadScript(url, callback) {
         var config = seed.config,
             node = document.createElement('script'),
             supportOnload = 'onload' in node;

         node.charset = config.charset || 'utf-8';
         node.setAttribute('data-module', url);

         // 绑定事件
         if (supportOnload) {
             node.onload = function() {
                 onload();
             };
             node.onerror = function() {
                 onload(true);
             }
         } else {
             node.onreadystatechange = function() {
                 if (/loaded|complete/.test(node.readyState)) {
                     onload();
                 }
             }
         }

         node.async = true;
         node.src = url;

         // 在IE6-8浏览器中,某些缓存会导致结点一旦插入就立即执行脚本
         currentlyAddingScript = node;

         // ref: #185 & http://dev.jquery.com/ticket/2709
         baseElement ? head.insertBefore(node, baseElement) : head.appendChild(node);

         currentlyAddingScript = null;

         function onload(error) {
             // 保证执行一次
             node.onload = node.onerror = node.onreadystatechange = null;
             // 删除脚本节点
             head.removeChild(node);
             node = null;
             callback(error);
         }
     }

     // 记录模块的状态信息
     Module.STATUS = {
         // 初始状态,此时模块刚刚新建
         INITIAL: 0,
         // 加载module.url指定资源
         FETCH: 1,
         // 保存module的依赖信息
         SAVE: 2,
         // 解析module的依赖内容
         LOAD: 3,
         // 执行模块,exports还不可用
         EXECUTING: 4,
         // 模块执行完毕,exports可用
         EXECUTED: 5,
         // 出错:请求或者执行出错
         ERROR: 6
     };

     function Module(url, deps) {
         this.url = url;
         this.deps = deps || [];                 // 依赖模块列表
         this.dependencies = [];                 // 依赖模块实例列表
         this.refs = [];                         // 引用模块列表,用于模块加载完成之后通知其引用模块
         this.exports = {};
         this.status = Module.STATUS.INITIAL;

         /*
          this.id
          this.factory
          */
     }

     Module.prototype = {
         constructor: Module,

         load: function() {
             var mod = this,
                 STATUS = Module.STATUS,
                 args = [];

             if (mod.status >= STATUS.LOAD) {
                 return mod;
             }
             mod.status = STATUS.LOAD;

             mod.resolve();
             mod.pass();
             mod.checkCircular();

             each(mod.dependencies, function(dep) {
                 if (dep.status < STATUS.FETCH) {
                     dep.fetch();
                 } else if (dep.status === STATUS.SAVE) {
                     dep.load();
                 } else if (dep.status >= STATUS.EXECUTED) {
                     args.push(dep.exports);
                 }
             });

             mod.status = STATUS.EXECUTING;

             // 依赖模块加载完成
             if (args.length === mod.dependencies.length) {
                 args.push(mod.exports);
                 mod.makeExports(args);
                 mod.status = STATUS.EXECUTED;
                 mod.fireFactory();
             }
         },

         /**
          * 初始化依赖模块
          */
         resolve: function() {
             var mod = this;

             each(mod.deps, function(id) {
                 var m, url;

                 url = id2Url(id, seed.config.baseUrl);
                 m = Module.get(url);
                 m.id = id;
                 mod.dependencies.push(m);
             });
         },

         /**
          * 传递模块给依赖模块,用于依赖模块加载完成之后通知引用模块
          */
         pass: function() {
             var mod = this;

             each(mod.dependencies, function(dep) {
                 var repeat = false;

                 each(dep.refs, function(ref) {
                     if (ref === mod.url) {
                         repeat = true;
                         return true;
                     }
                 });

                 if (!repeat) {
                     dep.refs.push(mod.url);
                 }
             });
         },

         /**
          * 解析循环依赖
          */
         checkCircular: function() {
             var mod = this,
                 STATUS = Module.STATUS,
                 isCircular = false,
                 args = [];

             each(mod.dependencies, function(dep) {
                 isCircular = false;
                 // 检测是否存在循环依赖
                 if (dep.status === STATUS.EXECUTING) {
                     each(dep.dependencies, function(m) {
                         if (m.url === mod.url) {
                             // 存在循环依赖
                             return isCircular = true;
                         }
                     });

                     // 尝试解决循环依赖
                     if (isCircular) {
                         each(dep.dependencies, function(m) {
                             if (m.url !== mod.url && m.status >= STATUS.EXECUTED) {
                                 args.push(m.exports);
                             } else if (m.url === mod.url) {
                                 args.push(undefined);
                             }
                         });

                         if (args.length === dep.dependencies.length) {
                             // 将exports作为最后一个参数传递
                             args.push(dep.exports);
                             try {
                                 dep.exports = isFunction(dep.factory) ? dep.factory.apply(global, args) : dep.factory;
                                 dep.status = STATUS.EXECUTED;
                             } catch (e) {
                                 dep.exports = undefined;
                                 dep.status = STATUS.ERROR;
                                 makeError("Can't fix circular dependency", mod.url + " --> " + dep.url);
                             }
                         }
                     }
                 }
             });
         },

         makeExports: function(args) {
             var mod = this,
                 result;

             result = isFunction(mod.factory) ? mod.factory.apply(global, args) : mod.factory;
             mod.exports = isPlainObject(mod.exports) ? result : mod.exports;
         },

         /**
          * 模块执行完毕,触发引用模块回调
          */
         fireFactory: function() {
             var mod = this,
                 STATUS = Module.STATUS;

             each(mod.refs, function(ref) {
                 var args = [];
                 ref = Module.get(ref);

                 each(ref.dependencies, function(m) {
                     if (m.status >= STATUS.EXECUTED) {
                         args.push(m.exports);
                     }
                 });

                 if (args.length === ref.dependencies.length) {
                     args.push(ref.exports);
                     ref.makeExports(args);
                     ref.status = STATUS.EXECUTED;
                     ref.fireFactory();
                 } else {
                     ref.load();
                 }
             });
         },

         /**
          * 发送请求加载资源
          */
         fetch: function() {
             var mod = this,
                 STATUS = Module.STATUS;

             if (mod.status >= STATUS.FETCH) {
                 return mod;
             }
             mod.status = STATUS.FETCH;

             loadScript(mod.url, function(error) {
                 mod.onload(error);
             });
         },

         onload: function(error) {
             var mod = this,
                 config = seed.config,
                 STATUS = Module.STATUS,
                 shim, shimDeps;

             if (error) {
                 mod.exports = undefined;
                 mod.status = STATUS.ERROR;
                 mod.fireFactory();
                 return mod;
             }

             // 非AMD模块
             shim = config.shim[mod.id];
             if (shim) {
                 shimDeps = shim.deps || [];
                 mod.save(shimDeps);
                 mod.factory = function() {
                     return getGlobal(shim.exports);
                 };
                 mod.load();
             }

             // 匿名模块
             if (anonymousMeta) {
                 mod.factory = anonymousMeta.factory;
                 mod.save(anonymousMeta.deps);
                 mod.load();
                 anonymousMeta = null;
             }
         },

         save: function(deps) {
             var mod = this,
                 STATUS = Module.STATUS;

             if (mod.status >= STATUS.SAVE) {
                 return mod;
             }
             mod.status = STATUS.SAVE;

             each(deps, function(d) {
                 var repeat = false;
                 each(mod.dependencies, function(d2) {
                     if (d === d2.id) {
                         return repeat = true;
                     }
                 });

                 if (!repeat) {
                     mod.deps.push(d);
                 }
             });
         }
     };

     /**
      * 初始化模块加载
      */
     Module.init = function() {
         var script, scripts, initMod, url;

         if (document.currentScript) {
             script = document.currentScript;
         } else {
             // 正常情况下,在页面加载时,当前js文件的script标签始终是最后一个
             scripts = getScripts();
             script = scripts[scripts.length - 1];
         }
         initMod = script.getAttribute("data-main");
         // see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
         url = script.hasAttribute ? script.src : script.getAttribute("src", 4);

         // 如果seed是通过script标签内嵌到页面,baseUrl为当前页面的路径
         seed.config.baseUrl = dirname(initMod || url);

         // 加载主模块
         if (initMod) {
             Module.use(initMod.split(","), noop, Module.guid());
         }

         scripts = script = null;
     };

     /**
      * 生成一个唯一id
      */
     Module.guid = function() {
         return "seed_" + (+new Date()) + (Math.random() + '').slice( -8 );
     };

     /**
      * 获取一个模块,如果不存在则新建
      *
      * @param url
      * @param deps
      */
     Module.get = function(url, deps) {
         return seed.modules[url] || (seed.modules[url] = new Module(url, deps));
     };

     /**
      * 加载模块
      *
      * @param {Array} ids 依赖模块的id列表
      * @param {Function} callback 模块加载完成之后的回调函数
      * @param {String} id 模块id
      */
     Module.use = function(ids, callback, id) {
         var config = seed.config,
             mod, url;

         ids = isString(ids) ? [ids] : ids;
         url = id2Url(id, config.baseUrl);
         mod = Module.get(url, ids);
         mod.id = id;
         mod.factory = callback;

         mod.load();
     };

     // 页面已经存在AMD加载器或者seed已经加载
     if (global.define) {
         return;
     }

     define = function(id, deps, factory) {
         var currentScript, mod;

         // define(factory)
         if (isFunction(id)) {
             factory = id;
             deps = [];
             id = undefined;

         }

         // define(deps, factory)
         else if (isArray(id)) {
             factory = deps;
             deps = id;
             id = undefined;
         }

         if (!id && (currentScript = getCurrentScript())) {
             id = currentScript.getAttribute("data-module");
         }

         if (id) {
             mod = Module.get(id);
             mod.factory = factory;
             mod.save(deps);
             mod.load();
         } else {
             anonymousMeta = {
                 deps: deps,
                 factory: factory
             };
         }
     };

     define.amd = {};

     require = function(ids, callback) {
         // require("test", callback)
         if (isString(ids)) {
             makeError("Invalid", "ids can't be string");
         }

         // require(callback)
         if (isFunction(ids)) {
             callback = ids;
             ids = [];
         }

         Module.use(ids, callback, Module.guid());
     };

     require.config = function(config) {
         mixin(seed.config, config);
     };

     // 初始化
     Module.init();
 })(window);

变量 seed 保存加载过的模块和一些配置信息。对象 Module 用来描述一个模块,Module.STATUS 描述一个模块的状态信息,define.js 加载完毕之后调用 Module.init 来初始化baseUrl 和主模块。当主模块调用require方法后,程序就会去加载相关的依赖模块。

有一个需要注意的地方是 动态创建的script,在脚本加载完毕之后,会立即执行返回的代码。对于AMD模块,其加载完毕之后会执行define方法,如果该模块为匿名模块(没有指定id),我们需要在onload回调中来处理该模块。在开始加载模块的时候,我们不会知道其依赖和工厂方法等信息,需要在这个模块加载完毕执行define方法才能获得。

4. 参考

Requirejs

Seajs

JavaScript AMD 模块加载器原理与实现的更多相关文章

  1. 一个简单的AMD模块加载器

    一个简单的AMD模块加载器 参考 https://github.com/JsAaron/NodeJs-Demo/tree/master/require PS Aaron大大的比我的完整 PS 这不是一 ...

  2. JS模块加载器加载原理是怎么样的?

    路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的 ...

  3. 构建服务端的AMD/CMD模块加载器

    本文原文地址:http://trock.lofter.com/post/117023_1208040 . 引言:  在前端开发领域,相信大家对AMD/CMD规范一定不会陌生,尤其对requireJS. ...

  4. 小矮人Javascript模块加载器

    https://github.com/miniflycn/webkit-dwarf 短小精悍的webkit浏览器Javascript模块加载器 Why 我们有许多仅基于webkit浏览器开发的应用 无 ...

  5. RequireJS 是一个JavaScript模块加载器

    RequireJS 是一个JavaScript模块加载器.它非常适合在浏览器中使用, 它非常适合在浏览器中使用,但它也可以用在其他脚本环境, 就像 Rhino and Node. 使用RequireJ ...

  6. 【模块化编程】理解requireJS-实现一个简单的模块加载器

    在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...

  7. [JavaScript] 前端模块加载简单实现(require)

    模块加载的简单实现 (function(win) { var baseUrl; var paths; var script_cache = {}; var script_queue = []; var ...

  8. 实现一个类 RequireJS 的模块加载器 (二)

    2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...

  9. 使用RequireJS并实现一个自己的模块加载器 (一)

    RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...

随机推荐

  1. 安装Axure7.0,完整教程,有验证码和汉化包

    以下内容由Axure中文网 » Axure7.0中文汉化语言包下载 axure汉化包 改编,特此声明 1.下载安装包 官方下载页面: http://www.axure.com/download 官网直 ...

  2. Xcode8控制台乱码的解决方式

    Xcode8里边 Edit Scheme-> Run -> Arguments, 在Environment Variables里边添加 OS_ACTIVITY_MODE = Disable ...

  3. Web Api 与 Andriod 接口对接开发经验

    最近一直急着在负责弄Asp.Net Web Api 与 Andriod 接口开发的对接工作! 刚听说要用Asp.Net Web Api去跟 Andriod 那端做接口对接工作,自己也是第一次接触Web ...

  4. iOS 键盘类型

    版权声明:本文为博主原创文章.请尊重作者劳动成果,转载请注明出处. UIKeyboardTypeDefault: UIKeyboardTypeASCIICapable: UIKeyboardTypeN ...

  5. HDU1102(最小生成树Kruskal)

    开学第三周.........真快尼 没有计划的生活真的会误入歧途anytime 表示不开心不开心不开心 每天都觉得自己的生活很忙 又觉得想做的事又没有完成 这学期本来计划重点好好学算法,打码码,臭臭美 ...

  6. SQL Server 系统表简介

    SQL Server 系统表简介 系统目录是由描述SQL Server 系统的数据库.基表.视图和索引等对象的结构的系统表组成.SQL Server 经常访问系统目录,检索系统正常运行所需的必要信息. ...

  7. 2014多校第四场1005 || HDU 4901 The Romantic Hero (DP)

    题目链接 题意 :给你一个数列,让你从中挑选一些数组成集合S,挑另外一些数组成集合T,要求是S中的每一个数在原序列中的下标要小于T中每一个数在原序列中下标.S中所有数按位异或后的值要与T中所有的数按位 ...

  8. 对ARM9哈佛结构的认识

    书本上都说ARM是哈佛结构,但是我总感觉好像看不出来.后来针对S3C2440的ARM9核进行分析,我有了自己的见解. 我的结论是“ARM9被称为是哈佛结构是从它拥有指令cache和数据cache”来说 ...

  9. C#基础:C#4.0权威指南 杂笔一

    1.c#中数组初始化的几种不同用法     int[] name = new int[NUM];       int[] name = {1, 2, 3, 4, 5, 6};       int[] ...

  10. BZOJ 1196 二分答案+并查集

    http://www.lydsy.com/JudgeOnline/problem.php?id=1196 题目大意:n个城市,m-1条路,每条路有一级公路和二级公路之分,你要造n-1条路,一级公路至少 ...