prototype.js 源码解读(02)
如果你想研究一些比较大型的js框架的源码的话,本人建议你从其最初的版本开始研读,因为最初的版本东西少,易于研究,而后的版本基本都是在其基础上不断扩充罢了,所以,接下来我不准备完全解读prototype.js的源码了,而是拿它一些常见的API来解读。
//定时器类,比起window.setInterval函数,该类能够使得回调函数不会被并发调用
    var PeriodicalExecuter = Class.create();//Class类创建的定时器类
    PeriodicalExecuter.prototype = {
        initialize: function(callback, frequency) {//在原型上定义构造函数
            this.callback = callback;//指定回调函数
            this.frequency = frequency;//指定执行频率
            this.currentlyExecuting = false;//默认不执行
            this.registerCallback();
        },
        //开始执行定时器
        registerCallback: function() {
            this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);//
        },
    //停止执行
        stop: function() {
            if (!this.timer) return;//判断不存在的情况
            clearInterval(this.timer);//清除定时器
            this.timer = null;//赋一个空指针,让人易于理解这是用来准备存放对象的
        },
    /*
    相当于回调函数的一个代理。
    在传统的setInterval函数中,时间一到,便强制执行回调函数,而这里加入了currentlyExecuting属性判断,
    则如果callback函数的执行时间超过了一个时间片,则阻止其被重复执行。
    */
        onTimerEvent: function() {
            if (!this.currentlyExecuting) {
                try {
                    this.currentlyExecuting = true;
                    this.callback(this);
                } finally {
                    this.currentlyExecuting = false;
                }
            }
        }
    }
给变量赋值的情况:
//为字符串对象添加方法,和前面为Number添加方法的原理相同
  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 += String.interpret(replacement(match));
            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() {
    //找到所有包括<script>的代码标记
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    //再对每个脚本删除<script>标记
    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) });
},
//利用浏览器本身的机制对Html字符串进行编码,例如将<转换为<
escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
},
//对Html进行解码
unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
        $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
        div.childNodes[0].nodeValue) : '';
},
/*
*获取查询字符串数组,例如通过document.location.toQueryParams()就可以得到由键和值组成的哈希表(用对象表示)。
*/
toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return {};
    return match[1].split(separator || '&').inject({}, function(hash, pair) {
        if ((pair = pair.split('='))[0]) {
            var name = decodeURIComponent(pair[0]);
            var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
            if (hash[name] !== undefined) {
                if (hash[name].constructor != Array)
                    hash[name] = [hash[name]];
                if (value) hash[name].push(value);
            }
            else hash[name] = value;
        }
        return hash;
    });
},
//将字符串转换为字符数组
toArray: function() {
    return this.split('');
},
succ: function() {
    return this.slice(0, this.length - 1) +
        String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
},
//将用"-"连接的字符串驼峰化
//例如:background-color转为backgroundColor
camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];
    var camelized = this.charAt(0) == '-'
        ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
        : parts[0];
    for (var i = 1; i < len; i++)
        camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
    return camelized;
},
//转换成大写形式
capitalize: function(){
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
},
//转换成下划线形式
underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
},
//转化成中划线
dasherize: function() {
    return this.gsub( 
                    
                