zoukankan      html  css  js  c++  java
  • jquery源码解析:jQuery数据缓存机制详解2

    上一课主要讲了jQuery中的缓存机制Data构造方法的源码解析,这一课主要讲jQuery是如何利用Data对象实现有关缓存机制的静态方法和实例方法的。我们接下来,来看这几个静态方法和实例方法的源码解析:

    data_user = new Data();    //对外使用的数据缓存对象
    data_priv = new Data();    //内部的数据缓存对象,内部使用

    jQuery.extend({      //在jQuery中添加静态方法
      acceptData: Data.accepts,   //调用Data构造函数的accepts静态方法

      hasData: function( elem ) {    //是否有这个属性
        return data_user.hasData( elem ) || data_priv.hasData( elem );
      },

      data: function( elem, name, data ) {
        return data_user.access( elem, name, data );
      },

      removeData: function( elem, name ) {
        data_user.remove( elem, name );
      },

      _data: function( elem, name, data ) {    //_代表私有的方法,不对外
        return data_priv.access( elem, name, data );
      },

      _removeData: function( elem, name ) {
        data_priv.remove( elem, name );
      }
    });

    静态方法,是直接调用Data原型上的方法,而上一课已经详细讲解了这个Data的原型,可以参照上一课。而在jQuery缓存系统中,我们经常使用的就是以下这几个实例方法:

    jQuery.fn.extend({  //在jQuery原型上添加实例方法

       data: function( key, value ) {   //一个参数时是获取数据,两个参数时是设置数据   

        var attrs, name,
          elem = this[ 0 ],  //找到一组元素中的第一个,如果是获取操作,只获取一个元素,如果是设置,就设置这一组元素
            i = 0,
              data = null;

        if ( key === undefined ) {  //当不传入参数时,就代表取这个元素的所有数据,比如:$("div").data();
          if ( this.length ) {   //如果有元素
            data = data_user.get( elem );  //获取这个元素的数据

            //下面这一段代码是来处理HTML5中的自定义属性data-xxx的。比如:<div id="div1" data-chao-ji="dan"></div>,$("#div1")[0].dataset.chaoJi等于"dan"(HTML5写法)。$("#div1").data("chaoJi")等于"dan"。jQuery缓存系统会把HTML5自定义属性data-xxx这种格式的数据自动缓存起来。

            if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {//元素是否是Element,元素是否有hasDataAttrs属性,第一次是没有的,也就是undefined。data_priv是内部使用的Data对象,不会影响到外部使用的Data对象data_user。
              attrs = elem.attributes;  //获取元素所有的属性
              for ( ; i < attrs.length; i++ ) {
                name = attrs[ i ].name;     //得到每一个属性的名字

                if ( name.indexOf( "data-" ) === 0 ) {    //如果元素中的属性名有data-开头的字符串,就进入到if语句
                  name = jQuery.camelCase( name.slice(5) );   //取data-后面的字符串,也就是chao-ji,然后转驼峰格式,也就是变成chaoJi。

                  dataAttr( elem, name, data[ name ] ); //把data-开头的属性名的值添加到缓存系统中
                }
              }
              data_priv.set( elem, "hasDataAttrs", true ); //设置此元素的hasDataAttrs属性值为true
            }
          }

          return data;
        }

        if ( typeof key === "object" ) {  //比如:$("#div1").data({name:"chaojidan",age:"25"});
          return this.each(function() {  //对每个元素,都在数据缓存中设置json中的属性值
            data_user.set( this, key );
          });
        }

        return jQuery.access( this, function( value ) {    //access的第一个参数是所有元素,第二个参数是回调,第三个参数是key值,第四个参数是value值。第五个参数的作用是来决定回调是用来设置数据还是获取数据的(true代表设置操作,false代表获取操作)。第六个参数和第七个参数是内部使用的,我们不用管。
          var data,
            camelKey = jQuery.camelCase( key );

          if ( elem && value === undefined ) {   //如果value为空的话,就代表参数只有一个,那么arguments。length=1 >1,返回false,因此代表获取操作,获取元素elem在缓存系统中的key属性值
            data = data_user.get( elem, key );   //获取数据
            if ( data !== undefined ) {   //如果找到,就直接返回
              return data;
            }

            data = data_user.get( elem, camelKey );   //如果没找到,就再找key的驼峰方式的属性值,比如:$("#div1").data("name-age"),它会先找name-age这种属性名的值,如果没找到,就找nameAge这种属性名的值。
            if ( data !== undefined ) {
              return data;
            }

            data = dataAttr( elem, camelKey, undefined ); //如果都没找到,就找HTML5自定义属性data-xxx的值,比如:元素div上的data-name-age的属性值。
            if ( data !== undefined ) {
              return data;
            }

            return;
          }

          this.each(function() {   //如果value存在,就代表是设置操作。就循环所有元素,对每个元素都设置
            var data = data_user.get( this, camelKey ); //先去缓存系统中取key的驼峰形式的属性值

            data_user.set( this, camelKey, value );   //然后把值设置给key的驼峰形式的属性名

            if ( key.indexOf("-") !== -1 && data !== undefined ) {  //如果key包含"-",并且之前取到的key的驼峰形式的属性值存在,那么就把此驼峰形式的属性值,赋给key这个属性名。举个例子:$("#div1").data("name-age","1"),这时缓存系统中会存储nameAge:1,然后我再$("#div1").data("name-age","2"),这时data = 1,nameAge:2,进入if语句,缓存系统会再存储name-age:1。
              data_user.set( this, key, value );
            }
          });
        }, null, value, arguments.length > 1, null, true );

      },

      removeData: function( key ) {    //删除数据
        return this.each(function() {
          data_user.remove( this, key );
        });
      }

    });

    function dataAttr( elem, key, data ) {   //key=chaoJi
      var name;

      if ( data === undefined && elem.nodeType === 1 ) {   //首先判断数据缓存中是否有此名字的属性值,如果没有,并且元素是Element,就进入if语句。如果数据缓存中已经有了此名字的属性值,那么就直接返回这个值。意思就是:当HTML5的data-xxx的属性名xxx与jQuery通过data方法添加到数据缓存的属性名xxx是一样的,那么你通过data方法访问时,获取到的值是数据缓存中的xxx属性值,而不是HTML5的data-xxx的属性值,只有数据缓存没有这个xxx的属性值时,才会去取HTML5的data-xxx的属性值。
        name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();  //rmultiDash = /([A-Z])/g;取大写字母,也就是J,然后用-J代替J,这时key是chao-Ji,然后转小写,因此变成chao-ji。name= "data-chao-ji"
        data = elem.getAttribute( name );   //得到元素上的这个HTML5自定义属性的属性值"dan"

        if ( typeof data === "string" ) {    //如果属性值是字符串就保存到缓存系统
          try {
            data = data === "true" ? true :  
              data === "false" ? false :
                data === "null" ? null :
                  +data + "" === data ? +data :  //如果是数字字符串,就存入数字
                    rbrace.test( data ) ? JSON.parse( data ) :  //rbrace判断是否是一个json字符串,如果是就解析成json。
                      data;   //如果是字符串,就直接返回字符串
          } catch( e ) {}

          data_user.set( elem, key, data );
        } else {   //如果不是字符串就直接返回undefined,也就是说HTML5的data-xxx的属性值只能是一个字符串,如果不是,那么你通过jQuery的data(xxx)方法获取时,是获取不到的,返回undefined。
          data = undefined;
        }
      }
      return data;
    }

    缓存系统到此结束,下一课将讲解队列Queue的实现原理。

    大家不要以为这就是源码粘贴,其实里面的注释是非常重要的,有些复杂的,我都会举例子说明,因此看起来不会很难。请看里面的注释。

    加油!

  • 相关阅读:
    C#系列之聊聊.Net Core的InMemoryCache
    函数式编程之-重新认识泛型(2)
    函数式编程之-重新认识泛型(1)
    ThreadLocal源码深度剖析
    使用ThreadLocal
    详解Redis中两种持久化机制RDB和AOF(面试常问,工作常用)
    Cassandra
    一致性HASH算法在分布式应用场景使用
    柔性分布式事务关于异步解决方案MQ版
    AtomicReference
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4181630.html
Copyright © 2011-2022 走看看