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;
                }
            }
        }
    }

给变量赋值的情况:

赋`undefined`值:表明对象属性或方法不存在,或声明了变量但从未赋值。

赋`null`值:包含 `null` 的变量包含“无值”或“无对象”。换句话说,该变量没有保存有效的数、字符串、`boolean`、数组或对象。可以通过给一个变量赋 `null` 值来清除变量的内容。也表明这个变量是用来存放对象的。


//为字符串对象添加方法,和前面为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字符串进行编码,例如将<转换为&lt;
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(/_/,‘-‘);
},

//将字符串转换为可观察的形式。这里将转义字符写成转义前的字符串形式
inspect: function(useDoubleQuotes) {
    var escapedString = this.replace(/\\/g, ‘\\\\‘);
    if (useDoubleQuotes)
        return ‘"‘ + escapedString.replace(/"/g, ‘\\"‘) + ‘"‘;
    else
        return "‘" + escapedString.replace(/‘/g, ‘\\\‘‘) + "‘";
}
});


注:i:忽略大小写,g全局匹配,m多行匹配

String对象中的正则表达式法:

 

方法含义
match(pattern) 返回pattern中的子串或null
replace(pattern,replacement) 用replacement替换pattern
search(pattern) 返回字符串中pattern开始位置
split(pattern) 返回字符串按指定pattern拆分的数组

 

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

    /*判断枚举对象中的所有元素是否有满足指定迭代器的值(返回true),如果有则返回true,否则返回false
    */
    其原理和all方法类似
    any: function(iterator) {
        var result = false;
        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 || Prototype.K)(value, index));
        });
        return results;
    },

/*返回第一个能够使得迭代器返回true的枚举元素的值,如果没有true,则返回"undefined",即result未被赋值
*/
    detect: function(iterator) {
        var result;
        this.each(function(value, index) {
            if (iterator(value, index)) {
                result = value;
                throw $break;
            }
        });
        return result;
    },
     /*
    返回所有能够使得迭代器返回true的枚举元素,作为数组返回。
    */
    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;
    },



/**
 * Element 就象一个 java 的工具类,主要用来 隐藏/显示/销除 对象,以及获取对象的简单属性。
 *
 */
if (!window.Element) {
    var Element = new Object();
}

Object.extend(Element, {
    /**
     * 切换 显示/隐藏
     */
    toggle: function() {
        for (var i = 0; i < arguments.length; i++) {
            var element = $(arguments[i]);
            element.style.display =
                (element.style.display == ‘none‘ ? ‘‘ : ‘none‘);//三目运算符判断
        }
    },

    hide: function() {
        for (var i = 0; i < arguments.length; i++) {
            var element = $(arguments[i]);//将选中的参数赋值给element
            element.style.display = ‘none‘;//你懂的
        }
    },

    show: function() {
        for (var i = 0; i < arguments.length; i++) {
            var element = $(arguments[i]);
            element.style.display = ‘‘;
        }
    },

    /**
     * 从父节点中移除
     */
    remove: function(element) {
        element = $(element);
        element.parentNode.removeChild(element);
    },

    getHeight: function(element) {
        element = $(element);
        return element.offsetHeight;
    },

    /**
     * 是否拥有 class 属性值
     */
    hasClassName: function(element, className) {
        element = $(element);
        if (!element)
            return;
        var a = element.className.split(‘ ‘);
        for (var i = 0; i < a.length; i++) {
            if (a[i] == className)
                return true;
        }
        return false;
    },

    /**
     * 为对象添加 class 属性值
     */
    addClassName: function(element, className) {
        element = $(element);
        Element.removeClassName(element, className);
        element.className += ‘ ‘ + className;
    },

    /**
     * 为对象移除 class 属性值
     */
    removeClassName: function(element, className) {
        element = $(element);
        if (!element)
            return;
        var newClassName = ‘‘;
        var a = element.className.split(‘ ‘);
        for (var i = 0; i < a.length; i++) {
            if (a[i] != className) {
                if (i > 0)
                    newClassName += ‘ ‘;
                newClassName += a[i];
            }
        }
        element.className = newClassName;
    },

// removes whitespace-only text node children
    cleanWhitespace: function(element) {
        var element = $(element);
        for (var i = 0; i < element.childNodes.length; i++) {
            var node = element.childNodes[i];
            if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
                Element.remove(node);
        }
    }
});



 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。