Home >Database >Mysql Tutorial >jquery源码解析:proxy,access,swap,isArraylike详解

jquery源码解析:proxy,access,swap,isArraylike详解

WBOY
WBOYOriginal
2016-06-07 15:38:131289browse

jQuery的工具方法,其实就是静态方法,源码里面就是通过extend方法,把这些工具方法添加给jQuery构造函数的。 jQuery.extend({ ...... guid: 1, //唯一标识符,跟事件有关。举个例子:function show(){alert(this);}, $("#input1").click(show),$("#input2

jQuery的工具方法,其实就是静态方法,源码里面就是通过extend方法,把这些工具方法添加给jQuery构造函数的。

jQuery.extend({ 

  ...... 

  guid: 1,    

  //唯一标识符,跟事件有关。举个例子:function show(){alert(this);}, $("#input1").click(show),$("#input2").click(function(){$("#input1").off()}),这里的show方法是事件方法,所以通过off取消掉事件绑定,可以很容易找到事件方法show。但是如果把 $("#input1").click(show)改成 $("#input1").click($.proxy(show,window)),这时show不是事件方法,而是普通方法,那么通过off取消的时候,它是怎么找到这个普通方法show的,其实就是通过guid,因为guid会累加,所以是唯一的,因此可以找到。请看下个方法就知道详情了。

  proxy: function( fn, context ) {    

    //改变方法(函数)执行的this指向。举例:$.proxy(show,document),想给show传参的话,有两种方式:var fn = $.proxy(show,document,1,2);fn(3,4)。最终show执行时就会变成show(1,2,3,4),proxy返回一个函数,调用fn时,就会执行show方法。
    var tmp, args, proxy;

    if ( typeof context === "string" ) {   //这里处理特殊调用情况,比如:$.proxy(obj,"show")(正常写法$.proxy(obj.show,obj)),show方法执行时,this指向的obj,并且show是obj的属性方法.var obj = { show: function(){}}。
      tmp = fn[ context ];
      context = fn;
      fn = tmp;
    }

    if ( !jQuery.isFunction( fn ) ) {
      return undefined;
    }

    args = core_slice.call( arguments, 2 );  //传入的参数,相当于例子的[1,2]
    proxy = function() {
      return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );  //把[3,4]和[1,2]合并成[1,2,3,4]
    };

    proxy.guid = fn.guid = fn.guid || jQuery.guid++;

    //第一次时,fn.guid(show.guid)是undefined,proxy.guid = fn.guid = 1,show.guid =1, 

    //function() {return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) )}.guid=1,唯一标识,取消绑定时,可以用到。

    return proxy;
  },

  //$().css(),$().attr(),通过参数的不同,实现get/set。参数的个数,以及参数的类型。$("div").css("width"),获得第一个div元素的width,$("div").css("width",100)设置所有的div元素的width。$("div").css({width:100,height:200}),也是设置所有的div元素,尽管只有一个参数,但是类型不一样。JQuery中有很多这种方法,所以统一用access实现。

  access: function( elems, fn, key, value, chainable, emptyGet, raw ) {

    //elems操作的元素,可能是一个集合。fn是一个回调函数(有区别的在回调函数中处理,比如,css设置样式,attr设置属性)。key和value就是属性名和属性值。chainable为true,设置,为false就获取。
    var i = 0,
      length = elems.length,
      bulk = key == null;

    if ( jQuery.type( key ) === "object" ) {//处理这种类型$("div").css({width:100,height:200})
      chainable = true;
      for ( i in key ) {
        jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
      }

    }

    else if ( value !== undefined ) {   //处理这种$("div").css("width",100)
      chainable = true;

      if ( !jQuery.isFunction( value ) ) {
        raw = true;    //字符串(数字)时
      }

      if ( bulk ) {   //如果没有key值
        if ( raw ) {   //如果value是字符串(数字)
          fn.call( elems, value );   //调用回调方法
          fn = null;   //把回调方法赋为空

        }

        else {     //如果是函数,这里面的不用深入理解
          bulk = fn;
          fn = function( elem, key, value ) {
            return bulk.call( jQuery( elem ), value );
          };
        }
      }

      if ( fn ) {    //如果没有key值,并且value是字符串(数字),这里就为null,不会执行
        for ( ; i           fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
        }
      }
    }

    return chainable ?     //获取时,chainable为false
        elems :     //设置时,chainable为true,直接返回元素,进行后续的链式操作

          bulk ?   
            fn.call( elems ) :  //没有key值时,就回调
              length ? fn( elems[0], key ) : emptyGet;  //有key值时,判断元素有没有元素,有的话就获取第一个元素的key值(属性名的值),没有元素的话,就返回emptyGet。
  },

  now: Date.now,  //当前时间距离1970年的毫秒数,相当于(new Date()).getTime()

  //以下方法是处理这种情况的:

  //

$("#div1").get(0).offsetWidth取到的是0,因为它是display:none,不存在DOM树中。$("#div1").width()取到的是100,为啥jQuery可以。因为jQuery会对display:none的元素进行处理,变成

  swap: function( elem, options, callback, args ) {  //css的转换,内部使用
    var ret, name,
      old = {};

    for ( name in options ) {    

      //保存老样式,插入新样式。这里假设options={width:100px;height:100px;background:red;display:block;visibility:hidden;position:absolute}

      //elem.>
      old[ name ] = elem.style[ name ]; 
      elem.style[ name ] = options[ name ];
    }

    ret = callback.apply( elem, args || [] );  

    //通过插入的新样式来获取元素的css值,callback = function(args){ if(args不是[]) return this[args]},args= offsetWidth;

    for ( name in options ) {       //恢复老样式
      elem.style[ name ] = old[ name ];
    }

    return ret;
  }

  ......

})

最后讲一下这个方法:

function isArraylike( obj ) {//判断是否是数组,类数组,带length的json,是的话就返回真
  var length = obj.length,
  type = jQuery.type( obj );

  if ( jQuery.isWindow( obj ) ) {  //担心window对象有length属性
    return false;
  }

  if ( obj.nodeType === 1 && length ) {  

  //元素节点对象,并且有length属性,返回真。document.getElementsByTagName("div")和body.childNodes都不是这种情况。可能用于内部调用,这里如果有谁知道的,可以告诉我。

    return true;
  }

  return type === "array" || type !== "function" &&   //不能是函数,因为函数也可能有length属性
    ( length === 0 ||typeof length === "number" && length > 0 && ( length - 1 ) in obj );

    //typeof length === "number" && length > 0 && ( length - 1 ) in obj )处理{0:"a",1:"b",length:2}这种情况。length === 0处理arguments为空的时候,就是不传入函数任何数据,这时函数中的arguments的length为0,但是是类数组。document.getElementsByTagName("div")和body.childNodes也是类数组。
}

 

 

加油!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn