`

jQuery data

 
阅读更多

但这不是jQuery想要的

jQuery要解决的是对应元素的缓存数据。

例如,我们用document.getElementById获得了一个元素element,然后有一个对应的参数value的属性名是key,那么我们想保存到缓存里,那么我们需要告诉缓存element、key、value才能保存数据,而想要获得这个值,则要告诉缓存element和key,才能得到value。

所以jQuery的缓存实际上是直接绑定到对象中的。

为什么?因为这样简单啊。

用上面的方法,先要将element转成字符串或者数字对应缓存里的对象,然后再用该对象来缓存不同key的value……这……太……麻……烦……了!!

实际上,由于Javascript没有Hash值方法,所以对象转字符串或数字并没有太好的方法,当然绑一个ID在元素上除外。

 

做一个别人一般不会用的令牌

但是绑定在对象上有一个问题,如果属性名用什么呢?

如果这个属性名别人也拿去用就悲剧了,比如我用.cache绑定数据,但是另一个库也有.cache来绑定数据,就……

所以,jQuery做了一个正常情况下别人不会用的令牌。

jQuery.expando = "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" );

replace函数将core_verision中的非数字全部替换掉,所以最后这个令牌是一个jQuery后面加一个随机数,比如:

  jQuery20018518865841457738

 

jQuery.hasData

jQuery.hasData = function( elem ) {
    elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
    return !!elem && !isEmptyDataObject( elem );
};

从这个函数可以看出,如果elem是DOM Element对象,则数据存在jQuery.cahe中,否则存在存在elem对象中。

 

jQuery.data & jQuery.removeData

jQuery.data = function( elem, name, data ) {
    return internalData( elem, name, data, false );
};
jQuery.removeData = function( elem, name ) {
    return internalRemoveData( elem, name, false );
};

他们分别调用了internalData和internalRemoveData。

注意专用接口jQuery._data和jQuery._removeData传的最后一个值有些不同。

这个后面会说到。

jQuery._data = function( elem, name, data ) {
    return internalData( elem, name, data, true );
};
jQuery._removeData = function( elem, name ) {
    return internalRemoveData( elem, name, true );
};

 

internalData

复制代码
function internalData( elem, name, data, pvt /* Internal Use Only */ ){
    // 判断该对象能不能绑定数据
    if ( !jQuery.acceptData( elem ) ) {
        return;
    }

    var thisCache, ret,
        internalKey = jQuery.expando,
        getByName = typeof name === "string",

        // 由于IE6-7的DOM节点引用的垃圾回收问题,需要分开处理DOM节点和JS对象
        // 真心想吐槽,这不是jQuery 2.0么!!!不是说不支持IE6-8么!!!
        isNode = elem.nodeType,

        // 如果是DOM节点,则使用jQuery.cache存储数据,否则使用elem本身
        cache = isNode ? jQuery.cache : elem,

        // 得到对象的ID号,如果是DOM节点则是其以令牌为属性名的属性值,否则是令牌
        id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;

    // 避免为了从一个根本没有数据的对象获取数据而浪费时间
    if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
        return;
    }

    // 如果没有ID
    if ( !id ) {
        // 如果是DOM节点,就给他一个ID
        if ( isNode ) {
            elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
        // 否则以令牌作为其ID
        } else {
            id = internalKey;
        }
    }

    // 如果对应ID的缓存不存在
    if ( !cache[ id ] ) {
        // 初始化缓存
        cache[ id ] = {};

        // 避免对JS对象使用JSON.stringify时暴露jQuery的元数据对象,所以给对象添加toJSON方法
        if ( !isNode ) {
            cache[ id ].toJSON = jQuery.noop;
        }
    }

    // 如果name是对象或者函数
    if ( typeof name === "object" || typeof name === "function" ) {
        // 如果是jQuery内部私用数据
        if ( pvt ) {
            // 则将数据保存在指定ID的对应缓存中
            cache[ id ] = jQuery.extend( cache[ id ], name );
        } else {
            //否则保存在指定ID对应缓存的data属性中
            cache[ id ].data = jQuery.extend( cache[ id ].data, name );
        }
    }

    //定位缓存中的数据
    thisCache = cache[ id ];

    // 区分内部私用以及公用来避免内部数据和用户定义数据的key重复导致的互相覆盖
    // 还有一个有趣的问题,为什么用户数据在data中,而内部数据直接在缓存对象里,而不是反过来呢?
    // 如果不是内部私用
    if ( !pvt ) {
        // 如果缓存中没有data属性,则初始化一个
        if ( !thisCache.data ) {
            thisCache.data = {};
        }

        // 定位缓存位置
        thisCache = thisCache.data;
    }

    // 如果data已定义,则是写入操作,写入数据
    if ( data !== undefined ) {
        thisCache[ jQuery.camelCase( name ) ] = data;
    }

    // 如果name是字符串,即通过字符串来获取数据
    if ( getByName ) {

        // 首先通过name来获取
        ret = thisCache[ name ];

        // 看看上面方法有没有得到数据
        if ( ret == null ) {

            // 如果没有,则用驼峰式name来获取
            ret = thisCache[ jQuery.camelCase( name ) ];
        }
    } else {
        // 不是则直接将数据传出
        ret = thisCache;
    }

    return ret;
}
复制代码

jQuery 2.0中data的实现依然同1.9版本差不多,当然这也不一定是IE6-7的原因才将DOM节点和JS对象分开处理的,我们知道JS引擎读取DOM数据的过程是较为费时费力的,从这个角度来看,将DOM节点的缓存设计在全局会是个比较快的方案。

这里还有两个有趣的问题:

  1. 如果传进去的data是函数,那么到底缓存了什么?
  2. 为什么用户数据在data中,而内部数据直接在缓存对象里,而不是反过来呢?

 

internalRemoveData

复制代码
function internalRemoveData( elem, name, pvt /* For internal use only */ ){
    // 判断该对象能不能绑定数据
    if ( !jQuery.acceptData( elem ) ) {
        return;
    }

    var thisCache, i, l,

        isNode = elem.nodeType,

        cache = isNode ? jQuery.cache : elem,
        id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

    // 如果缓存对象根本不存在,那么就不用删除了
    if ( !cache[ id ] ) {
        return;
    }

    // 如果name存在
    if ( name ) {

        // 定位缓存位置
        thisCache = pvt ? cache[ id ] : cache[ id ].data;

        // 如果缓存存在
        if ( thisCache ) {

            // 支持以空格分隔的字符串
            if ( !jQuery.isArray( name ) ) {

                // try the string as a key before any manipulation
                // 看看字符串name存不存在
                if ( name in thisCache ) {
                    // 定位要删除的缓存
                    name = [ name ];
                // 不存在证明传进来的是以空格分隔的字符串或者需要转成驼峰写法
                } else {

                    //转成驼峰写法
                    name = jQuery.camelCase( name );
                    //看看现在对不对
                    if ( name in thisCache ) {
                        name = [ name ];
                    //不对证明是以空格分隔的字符串
                    } else {
                        //以空格分隔字符串
                        name = name.split(" ");
                    }
                }
            } else {
                // 如果是数组,则预处理
                name = name.concat( jQuery.map( name, jQuery.camelCase ) );
            }

            // 遍历删除
            for ( i = 0, l = name.length; i < l; i++ ) {
                delete thisCache[ name[i] ];
            }

            // 如果缓存非空,则退出,证明缓存如果都空了,就要删掉它
            if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
                return;
            }
        }
    }

    // 如果不是私有的
    if ( !pvt ) {
        // 删除data属性
        delete cache[ id ].data;

        // 如果缓存对象并非空的,证明可能还有些私有属性存储了,退出
        if ( !isEmptyDataObject( cache[ id ] ) ) {
            return;
        }
    }

    // 到这里已经所有缓存数据都没有了,可以清理ID之类的东西了
    // 如果是DOM节点
    if ( isNode ) {
        // 清理数据
        jQuery.cleanData( [ elem ], true );

    // 看看能不能用delete方法删除
    // 还要判断cache本身是不是window对象,否则会抛错
    } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
        delete cache[ id ];

    // 如果不能删除则设为null
    } else {
        cache[ id ] = null;
    }
}
复制代码

 

jQuery.fn.data

复制代码
jQuery.fn.data = function( key, value ) {
    var attrs, name,
        elem = this[0],
        i = 0,
        data = null;

    // 如果key没有被定义,即要得到所有数据
    if ( key === undefined ) {
        // 如果长度不为0
        if ( this.length ) {
            // 用jQuery.data获取第一个元素的数据
            data = jQuery.data( elem );
            
            // 如果元素是节点,对应的内部数据parsedAttrs不存在
            if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
                // 从attrubutes中获取数据
                attrs = elem.attributes;
                // 遍历
                for ( ; i < attrs.length; i++ ) {
                    name = attrs[i].name;
                    
                    // 看看属性名是不是data-xxx,就是要支持HTML5 data-Attributes
                    if ( !name.indexOf( "data-" ) ) {
                        // 是则数据名为data-后面的字符串
                        name = jQuery.camelCase( name.slice(5) );

                        // 数据值通过daataAttr获取
                        dataAttr( elem, name, data[ name ] );
                    }
                }
                // 保存到对应内部缓存parsedAttrs中
                jQuery._data( elem, "parsedAttrs", true );
            }
        }

        return data;
    }

    // 如果key是对象,则通过jQuery.data设置多个属性
    if ( typeof key === "object" ) {
        return this.each(function() {
            jQuery.data( this, key );
        });
    }

    // 否则用access操作链式或不用链式
    return jQuery.access( this, function( value ) {

        // 如果value没有定义,则是读取操作
        if ( value === undefined ) {
            // 如果有第一个元素,则返回对应的数据,否则为空
            return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
        }

        // 设置操作调用jQuery.data来赋值
        this.each(function() {
            jQuery.data( this, key, value );
        });
    }, null, value, arguments.length > 1, null, true );
};
复制代码

这个方法主要是支持了HTML5 data-Attributes。

我们可以发现,实际上jQuery最终也把data-Attributes数据也保存到缓存中,这样是为了不再DOM和JS引擎中频繁读取。

 

jQuery.fn.removeData

jQuery.fn.removeData = function( key ) {
    return this.each(function() {
        jQuery.removeData( this, key );
    });
}

这个就很简单法了,只是遍历所有元素使用removeData而已。

 

dataAttr

复制代码
function dataAttr( elem, key, data ) {
    // 从data-*获取数据
    if ( data === undefined && elem.nodeType === 1 ) {

        // 预处理name,将驼峰式替换成data-*-*形式
        var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();

        // 尝试获取该attribute的数据
        data = elem.getAttribute( name );

        // 如果数据是字符串
        if ( typeof data === "string" ) {
            try {
                // 如果数据是"true",则为true
                data = data === "true" ? true :
                // 如果数据是"false",则为false
                data === "false" ? false :
                // 如果数据时"null",则为null
                data === "null" ? null :
                // 将字符串转成数字,再转成字符串看看有没有改变,没改变则证明是数字
                +data + "" === data ? +data :
                // 否则测试数据是否是以{}包裹,是则尝试转成对象
                rbrace.test( data ) ? jQuery.parseJSON( data ) :
                    //否则就当它是普通字符串
                    data;
            } catch( e ) {}

            //保存数据
            jQuery.data( elem, key, data );

        // 否则数据未定义
        } else {
            data = undefined;
        }
    }

    return data;
}
分享到:
评论

相关推荐

    jquery中data的用法案例

    在jQuery库中,`data()`方法是一个非常实用的功能,它允许我们存储和检索与DOM元素关联的数据。这个方法是jQuery扩展JavaScript原生DOM操作的重要部分,使得数据绑定变得更加方便和灵活。现在,让我们深入探讨一下`...

    jquery的data函数

    `jQuery`的`data()`函数是JavaScript库`jQuery`中一个非常重要的功能,它用于在DOM元素上存储和检索自定义数据。这个函数允许开发者在HTML元素上附加任意的JavaScript对象,而不会污染HTML的内置属性,使得数据管理...

    jQuery Data Linking 对象与对象之间属性的关联

    ASP.NET团队最近还向jQuery社区提交了被称为“data linking”的技术,Data Linking可以帮助你实现对象与对象之间属性的关联——当其中一方发生改变时另一方也随之改变。方便的实现页面中展现的数据与实际数据对象中...

    实测jquery data()如何存值

    ### jQuery的data()方法存储和获取值的机制 在讨论jQuery的data()方法如何存储和获取值之前,首先需要明白HTML元素上的data-*属性和jQuery内部存储的数据之间是如何交互的。根据提供的信息,jQuery的数据框架并不是...

    老生常谈JQuery data方法的使用

    JQuery 的 `data` 方法是用于在 jQuery 对象或 DOM 元素上存储和检索数据的关键功能。在本文中,我们将深入探讨 `data` 方法的使用,特别是在不同版本的 jQuery 中的行为差异。 首先,让我们澄清一下 `data` 方法的...

    逐一介绍Jquery data()、Jquery stop()、jquery delay()函数(详)

    首先给大家介绍jquery data()函数 jQuery中data()函数用于向被选元素附加数据,或者从被选元素获取数据。通过data()函数存取的数据都是临时数据,一旦页面刷新,之前存放的数据都将不复存在。 一、jquery data()的...

    前端项目-jquery-data-remote.zip

    前端项目-jquery-data-remote,jquery data remote是一个插件,它简化了执行api/remote请求和将响应注入页面的常见任务。也可以利用handlebars.js进行模板化。

    jqueryData:带有扩展数据,_data,hasData,removeData,acceptData,cache,deleteId和expando的jQuery 2.0.3

    jqueryData jquery.data.2.0.3.js jQuery 2.0.3版具有1.8.0版中的扩展功能。 例子用于查找元素的功能事件。 $(element).data('events') $._data('element', 'events')

    jQuery判断自定义属性data-val用法示例

    本文实例讲述了jQuery判断自定义属性data-val用法。分享给大家供大家参考,具体如下: jquery判断自定义属性data-val 1.css .active { color: red; } 2.html &lt;li data-val=1&gt;1 &lt;li data-val=2&gt;2 &lt;li data-...

    jQuery Mobile Data 属性

    jQuery Mobile Data 属性 jQuery Data 属性 jQuery Mobile 使用 HTML5 data-* 属性来为移动设备创建更具触摸友好性和吸引性的外观。 在下面的参考列表中,粗体显示的值为默认值。 按钮 在1.4 版本以后已废弃。...

    jQuery.data() 的实现方式

    `jQuery.data()` 是 jQuery 库中的一个核心方法,它用于在DOM元素上存储和检索数据。这个功能强大的工具使得开发者可以方便地与DOM元素关联任意的JavaScript对象或值,而无需污染HTML属性或使用全局变量。这篇博客...

    JavaScript and jQuery for Data Analysis and Visualization azw3

    JavaScript and jQuery for Data Analysis and Visualization 英文azw3 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    jquery静态模版常用组件

    7. **jQuery Data Tables**: 对于数据展示,jQuery Data Tables是一个强大且高度可定制的表格插件,可以轻松地将静态数据转换为交互式表格。 8. **jQuery Mobile**: 针对移动设备的开发,jQuery Mobile提供了一系列...

    方便打印的jQuery mobile data属性

    本文主要关注jQuery Mobile中的一个关键特性——data属性,这些属性用于定制和增强UI元素的功能和外观,使其更适合打印和学习。 首先,我们来看`data-role="button"`属性,它用于将HTML元素转化为jQuery Mobile的...

    jquery-data-bind:利用jquery实现简单的数据双向绑定,参考百度EUX的前端博客实现的

    jQuery的数据绑定利用jquery实现简单的数据双向绑定,参考百度EUX的前端博客实现的原始码从头开始做一个数据双向绑定并不是那么复杂。简单来说,需要实现以下三点:我们需要指定View中的UI元素和数据中的属性对应...

Global site tag (gtag.js) - Google Analytics