jQuery的内部方法:jQuery.access()讲解
2017-03-07 03:00

jQuery的内部方法jQuery.access()

一个方法的产生通常是基于应用的。而jQuery的这个access()方法,我们相信一开始也是为了处理注入"attr","css","html","text"等方法的解耦性而设想的。我们都知道jQuery的一大特点:链式调用。而链式调用是一个公用特性,没有必要在“attr”,"css"等各个方法中都做处理,或者引用考虑链式的操作。而这个jQuery.access()方法的目的就是,由它来处理一些功能是否需要链式调用,而“attr”,"css",“html”等方法则专注于他们的功能实现上,不用考虑链式调用的相关问题。

再一个,举例"css"方法,我们大家熟悉的“css”方法设置属性的调用有以下几种:

$("div").css("position","absolute");
$("div").css({color:"red",border:"1px solid blue"});
$("div").css(width:function(index,value){
    return parseFloat(value)*1.2+index;
});

调用方式分为三种:

@1:(name,value),传入名称和值的方式

@2:({key:value,key:value}),传入一个键值对map对象。

@3:(name:fn(index,value){}),传入一个名称和一个运算函数,函数接收两个值:index-元素中集合中的序列值,value-元素原来的值。

而jQuery.access()方法的另一个目标,就是实现这三种传值方式的格式化,然后调用相应的功能方法。“attr”,"css","html"等方法,不用考虑这些传值的方式,他们需要采用第一种方式来接收处理传值即可,其他的事情就交给access方法来解决。

这样,我们就明白了“jQuery.access”方法存在的目的和意义了,有两个:一是处理链式调用的操作问题,二是处理传值方式的格式化问题。

怀揣着目标我们再去看"jQuery.access"方法的源码,就容易理解了。

这个“jQuery.access”是定义在“jQuery”对象上的静态方法,作为工具方法来使用的,而我们要得到的链式调用的返回对象是jquery包装的DOM集合,所以需要将包装的DOM元素传递进来。

第一个参数:elms。

而“atrr”,"css","html"等方法的功能处理是截然不同的,所以需要一个他们自己的功能方法的回调。

第二个参数:fn。

传递键值对map对象是一个参数,传递name-value,name-callback是两个参数,所以我们需要key,value连个参数。

第三个参数:key。

第四个参数:value。

"attr","css"等设置值时是返回jquery包装对象,可以链式调用的,获取属性或样式时,返回的是相关属性样式值,是不可继续链式调用的。所以需要一个是否链式调用的值。

第五个参数:chainable。

当我们用$("...")获取对象进行操作时,如果获取的对象个数为0时,我们通过“attr”,"css"获取属性样式时,应该返回什么值呢?比如,我们attr要返回null,而html需要返回“”空字符串,这就需要再来一个参数。

第六个参数:emptyGet。

jQuery中还有一个数据绑定的方法“$('...').data”中也使用了“access()”方法,而通过data方法,我们可以这样调用:

$("div").data("message":{name:"girl",age:"18"});
$("div").data("loaded","yes");
$("div").data("callback",function(){
    ....
    ......
});

这里第三种写法的value值是一个函数,但是不需要它运行来返回属性值,它本身就是一个属性,需要保存的只是这个函数的一个引用,所以相比“attr”,"css"等方法,我们需要value是函数是,是否要运行,就要再来一个参数。

第七个参数:pass。

上面我们通过需求的方式分析了jQuery.access()方法的七个参数的作用。

jQuery.access()源码

access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
    var exec,
        bulk = key == null,
        i = 0,
        length = elems.length;

    // 如果key是对象,那么就是{key:value}传值方式,通过迭代调用access来获取需要的输入方式。
    if ( key && typeof key === "object" ) {
        for ( i in key ) {
            jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
        }
        chainable = 1;

        // key不是对象,是(name,value)传值时。
    } else if ( value !== undefined ) {
        //判断pass来获取exec标识符,决定value函数是否要执行。
        exec = pass === undefined && jQuery.isFunction( value );
        
        if ( bulk ) {
            // html(value)方法key为null,只有value时的处理。
            if ( exec ) {
                exec = fn;
                fn = function( elem, key, value ) {
                    return exec.call( jQuery( elem ), value );
                };

                // Otherwise they run against the entire set
            } else {
                fn.call( elems, value );
                fn = null;
            }
        }
        //执行相应的功能处理回调。
        if ( fn ) {
            for (; i < length; i++ ) {
                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
            }
        }
        //这里都为set方法,chainable为1。
        chainable = 1;
    }
    //根据chainable返回是否链式调用
    return chainable ?
            elems :

        // Gets,fn.call(elems)是html()方法获取内容,fn(elems[0],key)是其他方法获取属性值。
            bulk ?
                    fn.call( elems ) :
                    length ? fn( elems[0], key ) : emptyGet;
                    //emptyGet是元素个数为0时返回的空对象。
}

这时,我们再看jQuery.access()方法,就能很容易明白其中的逻辑了。

if ( key && typeof key === "object" ) {
        for ( i in key ) {
            jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
        }
        chainable = 1;
    }

这一段,用来处理输入的{key:value,key:value}键值对设值对象的参数标准化,通过迭代递归调用来处理。

else if ( value !== undefined ) {
        exec = pass === undefined && jQuery.isFunction( value );
 }

用来判断这个value函数是否要执行,data()函数中传入该值为false,其他功能函数都不传此值。

if ( bulk ) {
            // html(value)方法key为null,只有value时的处理。
            if ( exec ) {
                exec = fn;
                fn = function( elem, key, value ) {
                    return exec.call( jQuery( elem ), value );
                };

                // Otherwise they run against the entire set
            } else {
                fn.call( elems, value );
                fn = null;
            }
        }

这一段代码,来处理html(value)这种没有key值,单值设置的value值。

html: function( value ) {
   return jQuery.access( this, function( value ) {
      var elem = this[0] || {},
         i = 0,
         l = this.length;

      .......
      .....
   }, null, value, arguments.length );
}
jQuery.fn.extend({
   attr: function( name, value ) {
      return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
   },
   ......
 });
 
jQuery.extend({
 attr: function( elem, name, value, pass ) {
   var ret, hooks, notxml,
      nType = elem.nodeType;

   // don't get/set attributes on text, comment and attribute nodes
   if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
      return;
   }
   .....
 });

对比上面html方法和attr方法所需参数的不同,attr等方法的dom元素是通过参数传递的,而html方法的dom参数是通过this[0]获取的。

而bulk代码里面通过fn.call(elm,value)就是针对html()方法传递dom元素和单value值的。

其中的exec判断,并且包装了fn方法,是为了下面先运行value的求值函数,然后再赋值,同时也是跟其他传递dom参数的函数调用形式上进行同化。value不是函数的话,就将fn=null避免下面代码导致重复运行。

chainable = 1;

这一句表示作为set函数设置值时,是可以链式调用的。我认为这行代码多余,因为“attr”,"css"等方法都通过“arguments.length”传递了该值。

if ( fn ) {
     for (; i < length; i++ ) {
          fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
      }
}

这段代码是用来进行对元素集合中的每个dom元素进行set设置属性值,

exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value

这句代码是判断value是否是函数,是的话就先执行,再传递值。通过call的方式调用,那么这个value函数中的this就是元素本身了。value函数还传递了两个参数:

@1:“i”-元素的集合中的序列。

@2:“fn(elems[i],key)”-通过fn函数的获取值的方法得到元素对应属性的值。也是递归调用了。“attr”,“css”等方法不传value值时就可以作为get获取值的方法运行。

pass还是要传递的,这个还是对data()函数的处理。

return chainable ?
            elems :
            bulk ?
                  fn.call( elems ) :
                  length ? fn( elems[0], key ) : emptyGet;

最后return的代码分成连部分,chainable?为真时,返回elms元素,用做链式调用。chainable?为假时,进行get求值运算,并返回。

bulk为真时,表示没有key值,运行“fn.call(elms)”针对html()单参数的方法。bulk为假时,判断元素个数,有元素,则获取第一个元素的相关属性值,没有元素则返回null或者“”、{}(这个根据功能函数调用access()方法传递的emptyGet参数决定)。

聪明的你可能会疑问,那处理html()方法的调用怎么没有判断元素个数,你细看看上面html()方法中的代码:“var elem=this[0] || {}",它本身自己已经做了元素为空的处理了,所以这里不用判断元素个数。

jQuery.access()方法总结

通过本文的分析和详解,你可能觉得jQuery.access()方法功能这么强大,能包装这么多功能函数,怎么没出现在API中呢?其实你也发现了,这个方法虽然强大,但是使用限制太多,参数太多,用起来太麻烦,而且稍有不慎就会引起报错。所以只能作为内部方法使用,不适合作为API工具功能使用。


原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(2206)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1