.data()

Store arbitrary data associated with the matched elements or return the value at the named data store for the first element in the set of matched elements.

  根据jquery官网介绍,data给存储DOM关联的数据, 设置数据是对$选取的所有JQuery对象, 获取数据是对$选取的所有对象的第一个对象的存储的数据。

  设置语法格式 --- 设置单个数据 .data( obj )

  获取语法格式 --- 获取单个数据 .data()

      例子:

$( "body" ).data( "foo", 52 );
$( "body" ).data( "bar", { myType: "test", count: 40 } );
$( "body" ).data( { baz: [ 1, 2, 3 ] } );
$( "body" ).data( "foo" ); // 52
$( "body" ).data(); // { foo: 52, bar: { myType: "test", count: 40 }, baz: [ 1, 2, 3 ] }

 为什么需要 data 接口?

  web前端JS编程不可避免地,需要频繁地与DOM对象打交道。 HTML标签负责文档的结构, JS负责文档的行为, CSS负责文档的样式, JS通过document.getElementById()等接口获取DOM对象, 除了操作DOM对象的样式和属性等,往往在行为逻辑上, 脚本需要记录与DOM对象相关的数据 或者 某种状态值, 如果在js中直接使用全局变量记录此值, 具有很大的缺点, 首先不能直观体现此数据与DOM对象的关系, 其次全局变量有可能会发生命名冲突。

  例如,一个进度条DOM对象, 需要记录进度百分比值, 可以将此数据使用data接口记录到DOM对象上。

 

data 接口代码分析- .data( key, value )  设置单个数据

 

1、 JQuery对象的原型fn函数集合,添加了data接口,此接口判断如果为设置数据, 即arguments.length>1, 表示具有两个参数, 则执行红色代码三行, 将需要设置的DOM对象和需要设置的key和value , 传入 JQuery对象的data接口。

JQuery对象的data接口又做了些什么?

jQuery.fn.extend({
data: function( key, value ) { var i, name, data, elem = this[0], attrs = elem && elem.attributes; ..... return arguments.length > 1 ? // Sets one value this.each(function() { jQuery.data( this, key, value ); }) : // Gets one value // Try to fetch any internally stored data first elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; },

 

2、 jQuery.data函数分析

调用internalData函数并返回此函数的返回值。

jQuery.extend({
    cache: {},
......
    data: function( elem, name, data ) {
        return internalData( elem, name, data );
    },

 

3、 internalData 函数分析

此函数的第四个入参pvt可以忽略,执行过程有下面几个关键点:

#1 对于DOM对象nodeType为 1, 则缓存cache被设置为JQuery.cache。 此缓存空间即为 每个DOM对象data数据存储空间。

#2  对于第一次使用data接口, 需要对DOM元素, 生成一个唯一的ID: id = deletedIds.pop() || jQuery.guid++;

#3  然后在缓存空间 JQuery.cache中, 按照ID为下表为此DOM元素分配一个子空间: cache[ id ] = {}

#4 将此DOM子空间记录为 thisCache = cache[ id ];

#5 为此DOM子空间再开辟明确的data子空间: thisCache.data = {}; 并将此data子空间记录为thisCache

#6 设置数据 : thisCache[ jQuery.camelCase( name ) ] = data;

function internalData( elem, name, data, pvt /* Internal Use Only */ ) {

............
var ret, thisCache, internalKey = jQuery.expando, // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, ........... if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; } else { id = internalKey; } } if ( !cache[ id ] ) { // Avoid exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; } ............ thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } ...............
}

 

data 接口代码分析- .data( key)  获取单个数据

1、此接口判断如果为获取数据, 即arguments.length>1为false, 表示具有一个参数, 则返回 下面函数调用返回的结果: dataAttr( elem, key, jQuery.data( elem, key ) )

dataAttr又做了些什么?

jQuery.fn.extend({
data: function( key, value ) { var i, name, data, elem = this[0], attrs = elem && elem.attributes; ..... return arguments.length > 1 ? // Sets one value this.each(function() { jQuery.data( this, key, value ); }) : // Gets one value // Try to fetch any internally stored data first elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; },

 

2、 dataAttr 分析

查看注释, 此函数为 data不存在的情况下, 查HTML中 data-开头的相同属性值, 此处可以不用分析。

下面还是分析下下面函数调用执行, jQuery.data( elem, key )
function dataAttr( elem, key, data ) {
    // If nothing was found internally, try to fetch any
    // data from the HTML5 data-* attribute
    if ( data === undefined && elem.nodeType === 1 ) {

 

3、 jQuery.data( elem, key ) 获取单个数据

调用internalData函数并返回此函数的返回值。

我们下面分析 internalData函数第三个参数 data为空的情况。

jQuery.extend({
    cache: {},
......
    data: function( elem, name, data ) {
        return internalData( elem, name, data );
    },

 

4、 internalData 函数分析

此函数的第四个入参pvt可以忽略:

可以看到,对于获取单个数据情况, 还是从 JQuery.cache[DOM-ID].data中查找, 即下面这一句:

ret = thisCache[ name ];
function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
............... var ret, thisCache, internalKey = jQuery.expando, // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
.................
thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } .................// Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( typeof name === "string" ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; }

 

相关文章: