• jquery源码学习 最小系统


    先看看他的框架吧,了解了jquery的最小系统最小框架,大家等下就发现,他其实什么都没有做,这个就只是一个初始的骨架而已,当然,了解一下,对于我们应用他,还有扩展他应该是有所助益的.

    另,本人js纯菜鸟一枚,生怕误导了和我一样的菜鸟阶级朋友,所以请大家在看的同时多动手,呵呵,也希望路过的大牛们顺手指正.非常感谢.

    最小框架

    (function(window, undefined) {
    
        var 
        rootjQuery,
        core_version = "1.9.1",
    
    	_jQuery = window.jQuery,
    	_$ = window.$,
    
    	jQuery = function(selector, context) {
    	    return new jQuery.fn.init(selector, context, rootjQuery);
    	};
    
        jQuery.fn = jQuery.prototype = {
            jquery: core_version,
            constructor: jQuery,
            init: function(selector, context, rootjQuery) {
                return this;
            }
        };
    
        jQuery.fn.init.prototype = jQuery.fn;
    
        jQuery.extend = jQuery.fn.extend = function(dest, src) {
            for (var p in src) {
                dest[p] = src[p];
            }
            return dest;
        }
    
        jQuery.extend(jQuery, {
            noConflict: function(deep) {
                if (window.$ === jQuery) {
                    window.$ = _$;
                }
    
                if (deep && window.jQuery === jQuery) {
                    window.jQuery = _jQuery;
                }
    
                return jQuery;
            }
        });
    
        jQuery.extend(jQuery.fn, {
            method1: function(msg) {
                alert(msg);
                return this;
            }
            ,method2: function(msg) {
                alert(msg);
                return this;
            }
        });
    
        window.jQuery = window.$ = jQuery;
    
    })(window);
    
    

    jQuery.extend这个方法被我简写了,仅仅为了最小系统少几行代码,显得稍微清晰点而已.

    调用示例

    $().method1("Hello").method2("World!");
    

    链式调用风格,很方便的.

    如何扩展它?

    (function(jQuery, undefined) {
        jQuery.fn.extend(jQuery.fn, {
            method3: function(msg) {
                alert("method2:" + msg);
                return this;
            }
        });
    })(jQuery)
    

    经过这么扩展,我们就有method3这个新的方法了,和method1等方法的调用什么都是一样的.

    他是如何工作的?

    首先,所有的工作都是在一个函数里面完成的(不包括扩展的部分),这是一个自运行函数,如果您对什么是自运行函数不太了解,可以参考一下函数声明,函数表达式等的资料.

    先附上带代码注释吧,错漏的地方肯定不少,请大家批评指正.

    /*!
    * jQuery 最小系统
    * Date: 2013-04-25
    */
    
    //一个自运行的函数.
    (function(window, undefined) {
    
        var 
    
        //到jQuery(document)的一个引用,所有的jquery对象都将引用到他
        rootjQuery,
    
        //定义自己的版本号
        core_version = "1.9.1",
    
        //通过局部变量保存可能会被覆盖的window属性
        //如果用户调用jQuery.noConflict(deep)方法
        //则会恢复window.jQuery和window.$的值
        //目的是为了和别人和平共处互不冲突
    	_jQuery = window.jQuery,
    	_$ = window.$,
    
        //我个人的理解是按jQuery().m1().m2()这种调用方式导致这么处理?
        //这意味着jQuery()返回的对象与m1,m2应该有相同的prototype?this?
        //从而,假设返回的是new init()
        //那么init.prototype===jQuery.prototype    
        //那么...
    	jQuery = function(selector, context) { 
            //注释掉的这个有什么区别,有什么不妥吗?
            //如果使用了new的话,那么init函数中即使不return this应该也是可以的.
            //可见,new是在背后做了一些额外工作的
            //详情在本文的后面有说明
            //不过,刚查看到有人说了,这里用new,还有个隔离作用域的作用,表示不怎么明白,回去思考去,呵呵
            //关于这个隔离作用域,在文章后面有说明.
            //很多不该有的注释保留,是因为这个记录了本人的思考过程,嗯,由完全不明白,到明白一些些了,呵呵
            //return jQuery.fn.init(selector, context, rootjQuery);        
    	    return new jQuery.fn.init(selector, context, rootjQuery);
    	}; 
    	
        jQuery.fn = jQuery.prototype = {
            jquery: core_version,
            constructor: jQuery,//注释掉的话,有什么后果?在本例中倒是没什么
            init: function(selector, context, rootjQuery) {
                return this;
            }
        };
        //要让jquery()能复用jquery.fn的属性?
        jQuery.fn.init.prototype = jQuery.fn;
    
        //扩展对象,这个已经简化了,所以他的调用方式也就面目全非了
        jQuery.extend = jQuery.fn.extend = function(dest, src) {
            for (var p in src) {
                dest[p] = src[p];
            }
            return dest;
        }
    
        jQuery.extend(jQuery, {
            //避免冲突
            noConflict: function(deep) {
                if (window.$ === jQuery) {
                    window.$ = _$;
                }
    
                if (deep && window.jQuery === jQuery) {
                    window.jQuery = _jQuery;
                }
                return jQuery;
            }
        });
    
        jQuery.extend(jQuery.fn, {
            //定义自己的方法,没啥用
            method1: function(msg) {
                alert("method1:" + msg);
                //都记得要返回,从而实现链式调用
                return this;
            }
            , method2: function(msg) {
                alert("method2:" + msg);
                return this;
            }
        });
    
        //最顶级的jquery对象,所有其他jquery都将引用到他
        rootjQuery = jQuery(document);
    
        //不管这两属性是否会冲突,用了再说
        //等用户自己调用noConflict吧,如果冲突的话
        window.jQuery = window.$ = jQuery;
    
    })(window);
    

      

    补充一点,本人一直迷糊的地方,就是,看看一个对象是如何new出来的?

    最好当然是看ECMA文档了,下面的这个请在FF,Chrome下测试哦,IE就自动忽略吧.

    var JSEngine = function(fn) {
        var This = this;
        this.constructor = fn;
    
        //伪代码
        this.newObject = function() {
            var 
            o = {}//创建一个原生对象
            , _constructor = This.constructor;
    
            //查看构造函数的prototype类型是否为object
            //是则将对象的内部属性Prototype应用到它
            //否则此属性指向Object.prototype
            if (typeof _constructor.prototype === "object") {
                o.__proto__ = _constructor.prototype;
            }
            else {
                o.__proto__ = Object.prototype; //{}?
            }
    
            //调用构造函数
            var o2 = _constructor.apply(o, arguments);
            //如果返回的是对象,则返回这个o2,否则返回o
            if (typeof o2 === "object") {
                return o2;
            }
            else { return o; }
        }
    }
    

    从上面的代码可以看出,当使用new构建一个对象的时候,总是会返回一个object,这也是为什么前面使用:

    return new jQuery.fn.init(selector, context, rootjQuery);而不是return jQuery.fn.init(selector, context, rootjQuery);

    的原因(我个人猜想的啊,主要是我没有看出有别的不妥的地方,请过路的大牛指点啊!!!后来才明白,其实应该是后面说道的隔离作用域的原因啊)

    补充,刚从有些资料上看到,说此处用new是为了隔离作用域,哎,还得学习啊!!!

    测试代码如下:

    function fn1() {
        this.name = "AAA";
    }
    
    var js = new JSEngine(fn1);
    var o1 = js.newObject();
    var o2 = new fn1();
    alert(o1.name); //AAA
    alert(o2.name); //AAA
    alert(o1 instanceof fn1); //true
    alert(o2 instanceof fn1); //true
    

    那么,正常的函数调用会是什么样子呢?正常的函数调用的话看看下面的伪代码:

    function callFunction(fn, caller) {
        caller = caller || window;
        fn.apply(caller);
    }
    

     这里的caller与arguments.callee.caller是两码事.

       由上面的伪代码看出,fn函数体内部的this,指向的就是caller. 那么,这个caller是什么?就是函数的调用者,常见有如下形式:

    fn();//caller 默认就是全局对象
    x.y.fn();//caller就是x.y
    

    其实一般的场景都是这么简单的.那么,我们应该能够理解内部构造函数jQuery内部为什么是:

    return new jQuery.fn.init(selector, context, rootjQuery);
    

    而非

    return jQuery.fn.init(selector, context, rootjQuery);
    

    了吧? 前者得到的都是一个全新的对象(那么,作用域隔离的目的).后者的话,在init内部return this的话,总是得到同一个对象,那就是jQuery.fn, 这个意味着$()在任何地方都得到了一个唯一的相同的对象,这个就不能实现我们的目标了.

    强烈推荐大家看《深入理解JavaScript系列》

    最后,感谢John大神!!!

  • 相关阅读:
    使用 BenchmarkDotnet 测试代码性能
    【UWP】对 Thickness 类型属性进行动画
    【Win10】单元测试中捕获异步方法的指定异常
    【Win10】让 TextBlock 按字符换行
    全国天气预报信息数据 API 功能简介与代码调用实战视频
    5行代码实现微信小程序图片上传与腾讯免费5G存储空间的使用
    获取任意链接文章正文 API 功能简介
    开放数据接口 API 简介与使用场景、调用方法
    程序员如何开始做一个自己的 Side Project?
    VSCode 必装的 10 个高效开发插件
  • 原文地址:https://www.cnblogs.com/YFree/p/jquery.html
Copyright © 2020-2023  润新知