首页 > 代码库 > jQuery晦涩的底层工具方法们

jQuery晦涩的底层工具方法们

这里整理的是jQuery源码中一些比较晦涩难懂的、内部的、最底层的工具方法,它们多为jQuery的上层api方法服务,目前包括:

  • jQuery.access

jQuery.access: function( elems, fn, key, value, chainable, emptyGet, pass )

在jQuery的众多api方法中,许多方法都有一个非常重要和常见的特征:重载,简单来讲即参数的不同决定了方法的功能不同

例如我们最常使用的几个:jQuery.fn.val()、jQuery.fn.html()、jQuery.fn.attr()、jQuery.fn.text()、jQuery.fn.css()等等

从这些方法的身上,我们其实可以总结出它们之间一些共同具有的特征:

  • 所有的操作都是在元素节点上
  • 进行的操作都是get或set
  • 都有自己的处理函数
  • 都可以接受函数作为参数干预最终的结果
  • 具备链式调用的能力

源码解析:

// Multifunctional method to get and set values of a collection// The value/s can optionally be executed if it‘s a function/** 参数说明  * elems [object] 元素  * fn [function] 原始处理函数  * key [string|object] 属性名称/键值对列表  * value [type|function] 进行赋值的值/干预函数  * chainable [boolean] 是否可以链式调用  * emptyGet [type] 指定的空值,类型不定  * pass [boolean] 属性与jQuery方法同名时,是否调用jQuery的方法,在attr方法那里会用到      */access: function( elems, fn, key, value, chainable, emptyGet, pass ) {    var exec,        bulk = key == null,        i = 0,        length = elems.length;    // Sets many values    // 如果key是一个键值对对象,那么一定是在赋值,分解key然后递归调用    if ( key && typeof key === "object" ) {        for ( i in key ) {            // 可以看出,赋值操作都是可以继续链式调用,因为chainable直接被赋值为了1            jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );        }                // 这里仍然需要手动设置chainable的值为1        // 因为这里并没有return         chainable = 1;    // Sets one value    } else if ( value !== undefined ) {        // Optionally, function values get executed if exec is true        // 如果没传pass并且传入了干预函数        exec = pass === undefined && jQuery.isFunction( value );        // bulk = key == null        // 即没有传入key,但传了value进来        if ( bulk ) {            // Bulk operations only iterate when executing function values            // value是个函数的情况            if ( exec ) {                // 原始处理函数用exec保存起来                exec = fn;                // 把原本保存原始处理函数的变量fn重新用约定好的结构进行封装,以便后面统一进行调用                // 这里的key参数纯粹是为了在后面的调用处统一参数                // 注意这里的fn函数最后返回了原始处理函数的处理结果,为什么这样做呢?后面解释                fn = function( elem, key, value ) {                    return exec.call( jQuery( elem ), value );                };            // Otherwise they run against the entire set            } else {                // 这是最简单的情况,直接调用原始处理函数进行赋值                // 这种情况下的赋值操作到这里就已经完成了                // 所以在这里把fn置为了null,因为后面的if已经没有必要执行了                fn.call( elems, value );                fn = null;            }        }        // 剔除上面最简单那种情况,无论传不传key的值,这里的if都会执行        if ( fn ) {            for (; i < length; i++ ) {                // 这里的fn的值包含两种情况,一个是原始处理函数,一个是上面已经封装过的fn                // 这里最难理解的应该就是fn( elems[i], key )这句话了                // 首先无论是哪种情况,fn( elems[i], key )这句话一定是一个取值的操作                // 那么如果fn是原始处理函数,并且传入了key的值,取到的其实就是这个元素的原始属性值,把它作为第二个参数传入了干预函数( $("div").attr( "id", function( index, attr ){} ) )                // 如果fn是上面封装的函数,表示没有传入key值,则fn中的key和value都是undefined,但仍然仅凭元素就可以取得这个元素的原始属性值,哪种情况呢?如$("div").val("something")、$("div").text("something")                // 所以,fn( elems[i], key )这句话的作用也就清晰了,就是取得元素的原始属性值                // 搞懂了上面,这行代码也就不难理解了,这里设计的确实是巧啊                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );            }        }        // 同样,仍然是可以链式调用        chainable = 1;    }    // 如果可以链式调用,返回元素集即可,函数到此结束    // 如果不是,则证明是在取值    // 如果没传key,直接返回fn.call( elems ),如$("div").val()    // 如果传了key,则返回第一个元素的key对应的属性值或返回指定的空值emptyGet    return chainable ?        elems :        // Gets        bulk ?            fn.call( elems ) :            length ? fn( elems[0], key ) : emptyGet;}

 

  

jQuery晦涩的底层工具方法们