zoukankan      html  css  js  c++  java
  • jquery源码分析

             作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可。

             前段时间上班无聊之时,研究了下jquery的源码。现在记录下自己的成果,分享一下。

             下面是我自己琢磨和编写的jquery模型,里面有我所写的注释。

    /*
     * my-jquery-1.0
     */
    /*
     * 网上也有很多实现的版本,不过这是我在我自己的理解下写的,加上注释,希望可以解释清楚。
    */
    /*
     * 整个jquery包含在一个匿名函数中,专业点叫闭包,就是下面的形式,如(function(window,undefined){}(window))。
     * 闭包的定义在这里不太容易讲清楚,我只说下这样说的好处。
     * 1.使整个jquery中定义的变量成为局域变量,不会影响全局变量,个人觉得这也是jquery被成为轻量级的原因之一。
     * 2.增加jquery运行速度,因为局域变量运行速度高于全局变量。
     * 3.就像你看到,传入的window和undefined,可以自定义名字,方便编写。当然,现在你看到的仍是原来的写法,但是你可以看看jquery的min版本,一定是压缩的。
    */
    (function( window, undefined ) {
    var 
        /*jquery的定义,我们平时用的$和jQuery就是它。这里可以看出来真正的jQuery的对象是init方法产生的。
         *这样做采用了工厂模式,创建jQuery对象时不需要再new一个对象了。所以你可以发现,我们创建jQuery对象的方式是$(selector)或者是jQuery(selector)
         *原版的jQuery定义方法多了个上下文参数context,此处我省略了。
        */
        jQuery = function(selector){
            return new jQuery.fn.init(selector);
        },
        /*
         * 引用数据、对象以及字符串的方法
        */
        core_push = Array.prototype.push,
        core_slice = Array.prototype.slice,
        core_indexOf = Array.prototype.indexOf,
        core_toString = Object.prototype.toString,
        core_hasOwn = Object.prototype.hasOwnProperty,
        core_trim = String.prototype.trim;
        /*
         * jQuery对象的定义,这里去掉了所有的属性,只留下了init()。
         * jQuery的选择器采用了Sizzle,这里省略了,可以看出我只简单的返回了一个查询ID的方式。
         * jQuery的对象并不是这样简单的赋给了对象的一个属性,而是创建了一个数组。在这里忽略那些,只是赋给了obj属性。
         * 这里jQuery将原型赋给了jQuery的fn属性,所以我们如果要给jQuery对象扩展,只需要对jQuery.fn扩展就行。
        */
        jQuery.fn = jQuery.prototype = {
            init:function(selector){
                    this.obj = window.document.getElementById(selector);
                    return this;
            }
        };
        /*
         * 将jQuery的原型赋给init,这样是为了可以让jQuery对象,也就是init对象可以使用jQuery的扩展方法。
        */
        jQuery.fn.init.prototype = jQuery.fn;
        /*
         * jQuery的扩展方法,这个是jQuery的原版方法,我没做更改。
         * 方法的逻辑在这里不再说明,方法的效果就是,我们使用jQuery.extend可以扩展jQuery,而jQuery.fn.extend可以扩展jQuery对象。
        */
        jQuery.extend = jQuery.fn.extend = function() {
            var options, name, src, copy, copyIsArray, clone,
                target = arguments[0] || {},
                i = 1,
                length = arguments.length,
                deep = false;
    
            // Handle a deep copy situation
            if ( typeof target === "boolean" ) {
                deep = target;
                target = arguments[1] || {};
                // skip the boolean and the target
                i = 2;
            }
    
            // Handle case when target is a string or something (possible in deep copy)
            if ( typeof target !== "object" && !d.isFunction(target) ) {
                target = {};
            }
    
            // extend jQuery itself if only one argument is passed
            if ( length === i ) {
                target = this;
                --i;
            }
    
            for ( ; i < length; i++ ) {
                // Only deal with non-null/undefined values
                if ( (options = arguments[ i ]) != null ) {
                    // Extend the base object
                    for ( name in options ) {
                        src = target[ name ];
                        copy = options[ name ];
    
                        // Prevent never-ending loop
                        if ( target === copy ) {
                            continue;
                        }
    
                        // Recurse if we're merging plain objects or arrays
                        if ( deep && copy && ( d.isPlainObject(copy) || (copyIsArray = d.isArray(copy)) ) ) {
                            if ( copyIsArray ) {
                                copyIsArray = false;
                                clone = src && d.isArray(src) ? src : [];
    
                            } else {
                                clone = src && d.isPlainObject(src) ? src : {};
                            }
    
                            // Never move original objects, clone them
                            target[ name ] = d.extend( deep, clone, copy );
    
                        // Don't bring in undefined values
                        } else if ( copy !== undefined ) {
                            target[ name ] = copy;
                        }
                    }
                }
            }
    
            // Return the modified object
            return target;
        };
        /*
         * 这里实现了简单的ready绑定序列。
        */
        jQuery.extend({
            isReady:false,//文档加载是否完成的标识
            readyList:[],//函数序列
            //以下为工具方法,可忽略
            isArray : Array.isArray || function( obj ) {
                return jQuery.type(obj) === "array";
            },
    
            isWindow : function( obj ) {
                return obj != null && obj == obj.window;
            },
    
            isNumeric : function( obj ) {
                return !isNaN( parseFloat(obj) ) && isFinite( obj );
            },
    
            type : function( obj ) {
                return obj == null ?
                    String( obj ) :
                    class2type[ core_toString.call(obj) ] || "object";
            },
    
            isPlainObject : function( obj ) {
                // Must be an Object.
                // Because of IE, we also have to check the presence of the constructor property.
                // Make sure that DOM nodes and window objects don't pass through, as well
                if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
                    return false;
                }
    
                try {
                    // Not own constructor property must be Object
                    if ( obj.constructor &&
                        !core_hasOwn.call(obj, "constructor") &&
                        !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
                        return false;
                    }
                } catch ( e ) {
                    // IE8,9 Will throw exceptions on certain host objects #9897
                    return false;
                }
    
                // Own properties are enumerated firstly, so to speed up,
                // if last one is own, then all properties are own.
    
                var key;
                for ( key in obj ) {}
    
                return key === undefined || core_hasOwn.call( obj, key );
            },
            isFunction : function(obj){
                if(obj && typeof obj == 'function'){
                    return true;
                }
                return false;
            },
            //onload事件实现
            ready : function(fn){
                    //如果是函数,加入到函数序列
                    if(fn && typeof fn == 'function' ){
                        jQuery.readyList.push(fn);
                    }
                    //文档加载完成,执行函数序列。
                    if(jQuery.isReady){
                        for(var i = 0;i < jQuery.readyList.length ;i++){
                            fn = jQuery.readyList[i];
                            jQuery.callback(fn);
                        }
                        return jQuery;
                    }
                },
            //回调
            callback : function(fn){
                fn.call(document,jQuery);
            }
        });
        //模拟实现jQuery的html方法
        jQuery.fn.extend({
        html : function(html){
            if(html && typeof html == 'string'){
               this.obj.innerHTML = html;
               return this;
            }
            return this.obj.innerHTML;
        }
        });
        //导出对象
        window.$ = window.jQuery = jQuery;
        //判断加载是否完成
        var top = false;
        try {
            top = window.frameElement == null && document.documentElement;
        } catch(e) {}
        if ( top && top.doScroll ) {
            (function doScrollCheck() {
                try {
                    top.doScroll("left");
                    jQuery.isReady = true;
                    jQuery.ready();
                } catch(e) {
                    setTimeout( doScrollCheck, 50 );
                }
            })();
        }
    }(window));

             下面这个是测试文件。

    <html>
    <head>
    <script src="my-jquery-1.0.js" type="text/javascript"></script>
    <script type="text/javascript">
        $.extend({
            testExtend:function(){
                alert('extend success');
            }
        });
        $.ready(function(){
            alert($("test").html());
            $.testExtend();
        });
        $.ready(function(){
            $("test").html("modify success");
        });
        $.ready(function(){
            alert($("test").html());
        });
    </script>
    </head>
    <body>
        <div id="test">jquery src</div>
    </body>
    </html>

             两个文件复制出来放在同一个文件夹下面,就可以看到效果。希望各位有不同意见的可以提出来一起探讨。

  • 相关阅读:
    使用adb命令报错:解决办法
    appium+python+unittest自动化测试
    HTML自动化测试报告
    彻底解决appium 自动化测试时总是自动安装appium android input manager for unicode的问题
    selenium+python获取文本内容
    jenkins+robotframework中的Rebots Results不显示报告内容的问题
    robotframework+appium使用时的思考
    selenium unittest框架的断言知识
    jenkins配置问题三----用例运行pass,但是测试结果显示failure
    小程序中target与currentTarget的取值问题
  • 原文地址:https://www.cnblogs.com/zuoxiaolong/p/jquery_src.html
Copyright © 2011-2022 走看看