zoukankan      html  css  js  c++  java
  • prototype.js 1.4 原代码阅读(一)

    /**
     * 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号
     */
    var Prototype = {
      Version: '1.5.0_rc0',
      ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

      emptyFunction: function() {},
      K: function(x) {return x}
    }

    /**
     * 创建一种类型,注意其属性 create 是一个方法,返回一个构造函数。
     * 一般使用如下 
     *     var X = Class.create();  返回一个类型,类似于 java 的一个Class实例。
     * 要使用 X 类型,需继续用 new X()来获取一个实例,如同 java 的 Class.newInstance()方法。
     *
     * 返回的构造函数会执行名为 initialize 的方法, initialize 是 Ruby 对象的构造器方法名字。
     * 此时initialize方法还没有定义,其后的代码中创建新类型时会建立相应的同名方法。
     *
     * 如果一定要从java上去理解。你可以理解为用Class.create()创建一个继承java.lang.Class类的类。当然java不允许这样做,因为Class类是final的
     *
     */
    var Class = {
      create: function() {
        return function() {
          this.initialize.apply(this, arguments);
        }
      }
    }

    /**
     * 创建一个对象,从变量名来思考,本意也许是定义一个抽象类,以后创建新对象都 extend 它。
     * 但从其后代码的应用来看, Abstract 更多是为了保持命名空间清晰的考虑。
     * 也就是说,我们可以给 Abstract 这个对象实例添加新的对象定义。
     *
     * 从java去理解,就是动态给一个对象创建内部类。
     */
    var Abstract = new Object();

    /**
     * 获取参数对象的所有属性和方法,有点象多重继承。但是这种继承是动态获得的。
     * 如:
     *     var a = new ObjectA(), b = new ObjectB();
     *     var c = a.extend(b);
     * 此时 c 对象同时拥有 a 和 b 对象的属性和方法。但是与多重继承不同的是,c instanceof ObjectB 将返回false。
     */
    Object.extend = function(destination, source) {
      for (var property in source) {
        destination[property] = source[property];
      }
      return destination;
    }

    Object.inspect = function(object) {
      try {
        if (object == undefined) return 'undefined';
        if (object == null) return 'null';
        return object.inspect ? object.inspect() : object.toString();
      } catch (e) {
        if (e instanceof RangeError) return '...';
        throw e;
      }
    }

    /**
     * 这个方法很有趣,它封装一个javascript函数对象,返回一个新函数对象,新函数对象的主体和原对象相同,但是bind()方法参数将被用作当前对象的对象。
     * 也就是说新函数中的 this 引用被改变为参数提供的对象。
     * 比如:
     *     <input type="text" id="aaa" value="aaa">
     *     <input type="text" id="bbb" value="bbb">
     *     .................
     *     <script>
     *         var aaa = document.getElementById("aaa");
     *         var bbb = document.getElementById("bbb");

     *         aaa.showValue = function() {alert(this.value);}
     *         aaa.showValue2 = aaa.showValue.bind(bbb);
     *     </script>
     *  那么,调用aaa.showValue 将返回"aaa", 但调用aaa.showValue2 将返回"bbb"。
     *
     * apply 是ie5.5后才出现的新方法(Netscape好像很早就支持了)。
     * 该方法更多的资料参考MSDN
    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp
     * 还有一个 call 方法,应用起来和 apply 类似。可以一起研究下。
     */
    Function.prototype.bind = function() {
      var __method = this, args = $A(arguments), object = args.shift();
      return function() {
        return __method.apply(object, args.concat($A(arguments)));
      }
    }

    /**
     * 和bind一样,不过这个方法一般用做html控件对象的事件处理。所以要传递event对象
     * 注意这时候,用到了 Function.call。它与 Function.apply 的不同好像仅仅是对参数形式的定义。
     * 如同 java 两个过载的方法。
     */
    Function.prototype.bindAsEventListener = function(object) {
      var __method = this;
      return function(event) {
        return __method.call(object, event || window.event);
      }
    }

    /**
     * 将整数形式RGB颜色值转换为HEX形式
     */
    Object.extend(Number.prototype, {
      toColorPart: function() {
        var digits = this.toString(16);
        if (this < 16) return '0' + digits;
        return digits;
      },

      succ: function() {
        return this + 1;
      },

      times: function(iterator) {
        $R(0, this, true).each(iterator);
        return this;
      }
    });

    /**
     * 典型 Ruby 风格的函数,将参数中的方法逐个调用,返回第一个成功执行的方法的返回值
     */
    var Try = {
      these: function() {
        var returnValue;

        for (var i = 0; i < arguments.length; i++) {
          var lambda = arguments[i];
          try {
            returnValue = lambda();
            break;
          } catch (e) {}
        }

        return returnValue;
      }
    }

    /*--------------------------------------------------------------------------*/

    /**
     * 一个设计精巧的定时执行器
     * 首先由 Class.create() 创建一个 PeriodicalExecuter 类型,
     * 然后用对象直接量的语法形式设置原型。
     *
     * 需要特别说明的是 rgisterCallback 方法,它调用上面定义的函数原型方法bind, 并传递自己为参数。
     * 之所以这样做,是因为 setTimeout 默认总以 window 对象为当前对象,也就是说,如果 registerCallback 方法定义如下的话:
     *     registerCallback: function() {
     *         setTimeout(this.onTimerEvent, this.frequency * 1000);
     *     }
     * 那么,this.onTimeoutEvent 方法执行失败,因为它无法访问 this.currentlyExecuting 属性。

    * 而使用了bind以后,该方法才能正确的找到this,也就是PeriodicalExecuter的当前实例。
     */
    var PeriodicalExecuter = Class.create();
    PeriodicalExecuter.prototype = {
      initialize: function(callback, frequency) {
        this.callback = callback;
        this.frequency = frequency;
        this.currentlyExecuting = false;

        this.registerCallback();
      },

      registerCallback: function() {
        setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
      },

      onTimerEvent: function() {
        if (!this.currentlyExecuting) {
          try {
            this.currentlyExecuting = true;
            this.callback();
          } finally {
            this.currentlyExecuting = false;
          }
        }
      }
    }
    Object.extend(String.prototype, {
      gsub: function(pattern, replacement) {
        var result = '', source = this, match;
        replacement = arguments.callee.prepareReplacement(replacement);

        while (source.length > 0) {
          if (match = source.match(pattern)) {
            result += source.slice(0, match.index);
            result += (replacement(match) || '').toString();
            source  = source.slice(match.index + match[0].length);
          } else {
            result += source, source = '';
          }
        }
        return result;
      },

      sub: function(pattern, replacement, count) {
        replacement = this.gsub.prepareReplacement(replacement);
        count = count === undefined ? 1 : count;

        return this.gsub(pattern, function(match) {
          if (--count < 0) return match[0];
          return replacement(match);
        });
      },

      scan: function(pattern, iterator) {
        this.gsub(pattern, iterator);
        return this;
      },

      truncate: function(length, truncation) {
        length = length || 30;
        truncation = truncation === undefined ? '...' : truncation;
        return this.length > length ?
          this.slice(0, length - truncation.length) + truncation : this;
      },

      strip: function() {
        return this.replace(/^\s+/, '').replace(/\s+$/, '');
      },

      stripTags: function() {
        return this.replace(/<\/?[^>]+>/gi, '');
      },

      stripScripts: function() {
        return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
      },

    extractScripts: function() {
        var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
        var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
        return (this.match(matchAll) || []).map(function(scriptTag) {
          return (scriptTag.match(matchOne) || ['', ''])[1];
        });
      },

      evalScripts: function() {
        return this.extractScripts().map(function(script) { return eval(script) });
      },

      escapeHTML: function() {
        var div = document.createElement('div');
        var text = document.createTextNode(this);
        div.appendChild(text);
        return div.innerHTML;
      },

      unescapeHTML: function() {
        var div = document.createElement('div');
        div.innerHTML = this.stripTags();
        return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
      },

      toQueryParams: function() {
        var pairs = this.match(/^\??(.*)$/)[1].split('&');
        return pairs.inject({}, function(params, pairString) {
          var pair = pairString.split('=');
          params[pair[0]] = pair[1];
          return params;
        });
      },

      toArray: function() {
        return this.split('');
      },

      camelize: function() {
        var oStringList = this.split('-');
        if (oStringList.length == 1) return oStringList[0];

        var camelizedString = this.indexOf('-') == 0
          ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
          : oStringList[0];

        for (var i = 1, len = oStringList.length; i < len; i++) {
          var s = oStringList[i];
          camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
        }

        return camelizedString;
      },

      inspect: function() {
        return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
      }
    });

    String.prototype.gsub.prepareReplacement = function(replacement) {
      if (typeof replacement == 'function') return replacement;
      var template = new Template(replacement);
      return function(match) { return template.evaluate(match) };
    }

    String.prototype.parseQuery = String.prototype.toQueryParams;

    var Template = Class.create();
    Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
    Template.prototype = {
      initialize: function(template, pattern) {
        this.template = template.toString();
        this.pattern  = pattern || Template.Pattern;
      },

      evaluate: function(object) {
        return this.template.gsub(this.pattern, function(match) {
          var before = match[1];

    if (before == '\\') return match[2];
          return before + (object[match[3]] || '').toString();
        });
      }
    }

    var $break    = new Object();
    var $continue = new Object();

    var Enumerable = {
      each: function(iterator) {
        var index = 0;
        try {
          this._each(function(value) {
            try {
              iterator(value, index++);
            } catch (e) {
              if (e != $continue) throw e;
            }
          });
        } catch (e) {
          if (e != $break) throw e;
        }
      },

      all: function(iterator) {
        var result = true;
        this.each(function(value, index) {
          result = result && !!(iterator || Prototype.K)(value, index);
          if (!result) throw $break;
        });
        return result;
      },

      any: function(iterator) {
        var result = true;
        this.each(function(value, index) {
          if (result = !!(iterator || Prototype.K)(value, index))
            throw $break;
        });
        return result;
      },

      collect: function(iterator) {
        var results = [];
        this.each(function(value, index) {
          results.push(iterator(value, index));
        });
        return results;
      },

      detect: function (iterator) {
        var result;
        this.each(function(value, index) {
          if (iterator(value, index)) {
            result = value;
            throw $break;
          }
        });
        return result;
      },

      findAll: function(iterator) {
        var results = [];
        this.each(function(value, index) {
          if (iterator(value, index))
            results.push(value);
        });
        return results;
      },

      grep: function(pattern, iterator) {
        var results = [];
        this.each(function(value, index) {
          var stringValue = value.toString();
          if (stringValue.match(pattern))
            results.push((iterator || Prototype.K)(value, index));
        })
        return results;
      },

      include: function(object) {
        var found = false;

    this.each(function(value) {
          if (value == object) {
            found = true;
            throw $break;
          }
        });
        return found;
      },

      inject: function(memo, iterator) {
        this.each(function(value, index) {
          memo = iterator(memo, value, index);
        });
        return memo;
      },

      invoke: function(method) {
        var args = $A(arguments).slice(1);
        return this.collect(function(value) {
          return value[method].apply(value, args);
        });
      },

      max: function(iterator) {
        var result;
        this.each(function(value, index) {
          value = (iterator || Prototype.K)(value, index);
          if (result == undefined || value >= result)
            result = value;
        });
        return result;
      },

      min: function(iterator) {
        var result;
        this.each(function(value, index) {
          value = (iterator || Prototype.K)(value, index);
          if (result == undefined || value < result)
            result = value;
        });
        return result;
      },

      partition: function(iterator) {
        var trues = [], falses = [];
        this.each(function(value, index) {
          ((iterator || Prototype.K)(value, index) ?
            trues : falses).push(value);
        });
        return [trues, falses];
      },

      pluck: function(property) {
        var results = [];
        this.each(function(value, index) {
          results.push(value[property]);
        });
        return results;
      },

      reject: function(iterator) {
        var results = [];
        this.each(function(value, index) {
          if (!iterator(value, index))
            results.push(value);
        });
        return results;
      },

      sortBy: function(iterator) {
        return this.collect(function(value, index) {
          return {value: value, criteria: iterator(value, index)};
        }).sort(function(left, right) {
          var a = left.criteria, b = right.criteria;
          return a < b ? -1 : a > b ? 1 : 0;
        }).pluck('value');
      },

      toArray: function() {
        return this.collect(Prototype.K);
      },  zip: function() {
        var iterator = Prototype.K, args = $A(arguments);
        if (typeof args.last() == 'function')
          iterator = args.pop();

        var collections = [this].concat(args).map($A);
        return this.map(function(value, index) {
          return iterator(collections.pluck(index));
        });
      },

      inspect: function() {
        return '#<Enumerable:' + this.toArray().inspect() + '>';
      }
    }

    Object.extend(Enumerable, {
      map:     Enumerable.collect,
      find:    Enumerable.detect,
      select:  Enumerable.findAll,
      member:  Enumerable.include,
      entries: Enumerable.toArray
    });
    var $A = Array.from = function(iterable) {
      if (!iterable) return [];
      if (iterable.toArray) {
        return iterable.toArray();
      } else {
        var results = [];
        for (var i = 0; i < iterable.length; i++)
          results.push(iterable[i]);
        return results;
      }
    }

  • 相关阅读:
    Delphi编程 -- 视频捕获avicap32.pas源代码
    Delphi的DataSource事件
    InfoPower4000 wwGrid控件的一些应用技巧
    TwwDBGrid + TwwDBLookupCombo 下拉列表
    Delphi中TwwDBLookupCombo中属性的简单设置
    DevExpress中文说明--TdxCameraControl Object 摄像头组件
    如何Windows分页控件中增加统计功能
    Kibana:运用索引模式的 formatter 来探索 IP 信息
    Alertmanager高可用
    Prometheus高可用部署
  • 原文地址:https://www.cnblogs.com/liufei88866/p/1275878.html
Copyright © 2011-2022 走看看