Jquery 源码分析一: 整体架构、链式调用、插件接口

jQuery 整体架构:

JQuery框架的核心就是从HTML文档中匹配元素并对其执行操作,那么有两个问题值得我们思考?
  • jQuery 对象构建的方式?
  • jQuery 方法的调用方式?
jQuery 对象构建方式 实现的关键点:
1. 可以将jQuery类当做一个工厂方法来创建实例,并将这个方法放到jQuery.prototype 原型中
2. 对作用域进行处理,来分隔this,避免交互混淆
var aQuery = function(selector,context){
     //每次构建新的init 实例,来分隔this
     return new aQuery.prototype.init();
 }
 aQuery.prototype = {
     init : function(){
         this.age = 18;
         return this;
     },
     name : function(){},
     age : 20
 }

 console.log(aQuery()); 
 console.log(aQuery().name()); //报错:Uncaught TypeError: aQuery(...).name is not a function
访问jQuery类原型上的属性与方法:
既能做到隔离作用域还能使用jQuery原型对象的作用域,还能在返回实例中访问jQuery 的原型对象
实现的关键点:
jQuery.fn.init.prototype = jQuery.fn; //用jQuery 原型对象覆盖了init 构造器的原型对象
var aQuery = function(selector,context){
     return new aQuery.prototype.init();
 }
 aQuery.prototype = {
     init : function(){
         return this;
     },
     name : function(){
         return this.age;
     },
     age : 20
 }

 aQuery.prototype.init.prototype = aQuery.prototype;
 console.log(aQuery().name()); //20

jQuery 链式调用:

DOM 链式调用的处理:
1. 节约JS代码
2. 返回的都是同一个对象,可以提高代码的效率
关键点:
通过简单扩展原型方法并通过return this 的形式来实现跨浏览器的链式调用
利用JS下的简单工厂模式,来将所有对于同一个DOM对象的操作指定同一个实例
aQuery().init().name()
分解
a = aQuery();
a.init();
a.name();
//链式调用,返回当前实例的this,从而又可以访问自己的原型
var aQuery = function(selector,context){
     return new aQuery.prototype.init();
 }
 aQuery.prototype = {
     init : function(){
         this.age = 18;
         return this;
     },
     name : function(){
         this.age++;
         return this;
     }
 }
 console.log(aQuery.prototype.init().name()); //19

jQuery 插件接口:

jQuery 支持自己扩展属性,这个对外提供了一个接口,jQuery.fn.extend( )来对对象增加方法;
jQuery.extend 和 jQuery.fn.extend 其实是同指向同一方法的不同引用

jQuery.extend 对jQuery 本身的属性和方法进行了扩展
jQuery.fn.extend 对jQuery.fn 的属性和方法 进行了扩展
通过extend()函数可以方便快速的扩展功能,不会破坏jQuery 的原型结构
jQuery.extend = jQuery.fn.extend = function(){...} 这个是连等,也就是2个指向同一个函数,不过不怎么会实现不通过的功能呢? 这就是this 的力量了!
  • jQuery.extend 调用的时候,this 是指向jQuery对象的,所以这里扩展在jQuery上
  • jQuery.fn.extend 调用的时候,this 指向 fn 对象, jQuery.fn 和 jQuery.prototype 指向同一对象,扩展fn 就是扩展jQuery.prototype 原型对象
<script>
    jQuery.extend = jQuery.fn.extend = function(){
        /**
         * target:被扩展的对象
         * length:参数的数量
         * deep:是否深度复制
         */
        var options,name,src,copy,copyIsArray,clone,
            target = arguments[0] || {},
            length = arguments.length,
            i = 1,
            deep = false;
        //target 为第一个参数,如果第一个参数是boolean类型的值,则把target 的值赋值给deep
        if(typeof target === 'boolean'){
            deep = target;
            target = arguments[1] || {};
            // 将i 赋值为2,跳过前两个参数,方便 后面的for循环逻辑衔接
            i = 2;

        }
        // target 既不是对象也不是函数,则把target 设置为空对象
        if(typeof target !== "object" && jQuery.isFunction(target)){
            target = {};
        }
        //如果只有一个参数,则把jQuery 对象赋值给 target,即扩展到 jQuery 对象上
        if(length === i){
            target = this;
            //i 减1,指向 被扩展对象
            --i;
        }
        //开始遍历需要被扩展到target上的参数
        for(;i < length;i++){
            //处理第i个被扩展的对象
            if(options = arguments[i] !== null){
                //遍历第i 个对象所有可遍历的属性
                for(name in options){
                    //根据被扩展对象的键 获得目标对象相应值,并赋值给src
                    src = target[name];
                    //得到被扩展对象的值
                    copy = options[name];
                    //此处不比较src 和 copy 的原因是 避免自引用 造成栈溢出
                    if(target === copy){

                        continue;
                    }
                    //如果是深拷贝 且被拷贝的属性值本身是个对象
                    if(deep && copy && (jQuery.isPlainObject(copy) || copyIsArray = jQuery.isArray(copy))){
                        //如果是数组
                        if(copyIsArray){
                            // 将copyIsArray 重新设置为false,为下次遍历做准备
                            copyIsArray = false;
                            clone = src && jQuery.isArray(src) ? src : [];
                        }else{
                            //判断 被扩展的对象中src 是不是纯对象
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }
                        //递归调用extend 方法,继续深度遍历
                        target[name] = jQuery.extend(deep,clone,copy);
                        //如果不需要深度复制,则直接把copy
                    }else if(copy !== undefined){
                        target[name] = copy;
                    }
                }
            }
        }
        return target;
    }


</script>

总结:

  • 通过new jQuery.fn.init() 构建一个新的对象,拥有init构造器的prototype原型对象的方法
  • 通过改变prototype指针的指向,让这个新的对象也指向了jQuery 类的原型prototype
  • -

转载自:【http://www.cnblogs.com/aaronjs/p/3278578.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值