data有什么作用?

在我们平时js编码过程中,我们经常会向DOM元素中添加各种自定义属性,这样有一个弊端。
1、假设我们在DOM元素中添加了一个属性,这个属性指向了某个js对象。 dom1.ele = jsObj
2、当这个js对象发挥完作用后,我们已经用不到他了。这时候按理说应该把这个js变量清空,释放内存。大家都知道,如果一个js对象不存在任何外在引用的话,解释器会自动将其在内存中删除,这也是javascript相对于c++等手动管理内存的程序的优点。
3、但是这时候问题来了,因为DOM元素引用了这个js对象,尽管这个js对象已经没有存在的意义了,但是解释器是不会把他删除的。如果想要把其删除,我们可能需要将DOM元素的这个属性设置为null。
4、我们编写了这么多的代码,哪里能把 每个js对象是不是被DOM元素引用了都记住啊?
5、而且,假如DOM元素与js对象之间相互循环引用,根本就无法删除! 这就是内存泄漏
6、所以,为了避免这种情况的发生,我们要尽量避免 引用数据(这里的引用数据可以说是javascript对象) 直接依附在DOM对象上。
7、data就是用来搞定以上问题的方法。
data是如何搞定以上问题的?
首先来说一说jQuery中Data实现的大体思路:
1、首先我们创建一个数据缓存池,这个缓存池专门用来存储 向 DOM对象或者jQuery对象附加的额外数据。
2、当我们要向DOM对象或者jQuery对象附加额外数据的时候,我们附加的数据其实是保存于这个缓存池中
3、DOM对象或者jQuery对象生成一个额外属性,这个属性保存了 附加数据在缓存池中的‘门牌号'(位置或者索引)
4、当我们访问DOM对象或者jQuery对象的附加数据时,实际上是先取得其附加数据的门牌号,然后找到缓存池中对应门牌号的数据,进行操作。
大体思路讲完,那么来分析一下具体思路:
在jQuery中,有一个Data构造函数,每当运行这个构造函数时,就会生成一个实例。
jQuery默认会自动生成两个Data实例:
var dataPriv = new Data() jQuery私有的,我们尽量不要对这个实例进行操作。
var dataUser = new Data() 这个就是服务于用户了,我们使用data()方法都是对这个实例进行操作。
所有的Data实例都有以下属性:
expando: 值为字符串类型,每个Data实例的expando属性的值都不相同,用来区分不同的Data实例,类似于id的作用,expando的值就是上文中的额外属性。
uid: 这就是上文中的门牌号,初始为1,随着不同对象的附加数据的加入,自增长。
cache : 一个对象 {} ,这就是缓存池了。
来个实例:
$(document.body).data('aaa', 'value-aaa')
console.dir(document.body)
body对象有一个名为jquer210023......的额外属性,
这个属性的名称就是dataUser的expando的值
这个属性的值就是门牌号。
总结: data实际上就是对js对象或者DOM对象的额外属性做了一个集中的管理。对于那些不会产生内存泄漏的额外数据,我们也可以直接向js对象或者DOM对象附加。
好,理清楚上面的关系后,我们再来看一下源码:
define([
"../core",
"../var/rnotwhite",
"./accepts"
], function( jQuery, rnotwhite ) {
function Data() {
// Support: Android<4,
// Old WebKit does not have Object.preventExtensions/freeze method,
// return new empty object instead with no [[set]] accessor
Object.defineProperty( this.cache = {}, 0, {
get: function() {
return {};
}
});
// jQuery.expando = "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ) expando是一个jQuery的唯一标示
// 格式是:'jQuery\\d*' 也就是'jQuery'+ 多个数字。这里为啥要搞得这么麻烦呢?
// 应因为我们可能会创建多个Data对象,为了保证每个Data对象的expando属性的值不相等,所以这么搞
this.expando = jQuery.expando + Math.random();
}
Data.uid = 1; // Data函数的属性,'静态属性'
Data.accepts = jQuery.acceptData;
Data.prototype = {
key: function( owner ) {
// We can accept data for non-element nodes in modern browsers,
// but we should not, see #8335.
// Always return the key for a frozen object.
// 若owner在该缓存池中存在对应的缓存对象,则返回混存对象的key(是一个数字),
// 若owner在该缓存池中不存在对应的缓存对象,则在缓存池中为其创建一个缓存对象,并返回该缓存对象的key
if ( !Data.accepts( owner ) ) {
return 0;
}
var descriptor = {},
// Check if the owner object already has a cache key
// 检查owner对象在该缓存池中是否存在缓存
unlock = owner[ this.expando ]; // 是一个数字,用来作为缓存池中缓存对象的key
// If not, create one
// 如果没有,则创建一个
if ( !unlock ) {
unlock = Data.uid++;
// Secure it in a non-enumerable, non-writable property
// 给owner附加一个属性 owner[this.expando] = unlock ,并且该属性不能被枚举,
try {
descriptor[ this.expando ] = { value: unlock };
Object.defineProperties( owner, descriptor );
// Support: Android<4
// Fallback to a less secure definition
} catch ( e ) {
descriptor[ this.expando ] = unlock;
jQuery.extend( owner, descriptor );
}
}
// Ensure the cache object
// 确保owner对应的缓存对象已存在
if ( !this.cache[ unlock ] ) {
this.cache[ unlock ] = {};
}
// 返回unlock
return unlock;
},
set: function( owner, data, value ) {
// 设置owner对应的缓存对象
var prop,
// There may be an unlock assigned to this node,
// if there is no entry for this "owner", create one inline
// and set the unlock as though an owner entry had always existed
unlock = this.key( owner ), // 获取owner的对应的缓存对象在缓存池中的key(这里的key,是键值对中的键的意思)
cache = this.cache[ unlock ]; // 获取owner所对应的缓存对象
// Handle: [ owner, key, value ] args
// 根据传入参数的个数以及类型实现重载
if ( typeof data === "string" ) {
cache[ data ] = value;
// Handle: [ owner, { properties } ] args
} else {
// Fresh assignments by object are shallow copied
if ( jQuery.isEmptyObject( cache ) ) {
jQuery.extend( this.cache[ unlock ], data );
// Otherwise, copy the properties one-by-one to the cache object
} else {
for ( prop in data ) {
cache[ prop ] = data[ prop ];
}
}
}
// 返回缓存对象
return cache;
},
get: function( owner, key ) {
// 获取owner对象的名为key的属性值
// owner:是一个对象(可以是jQuery对象也可以是DOM对象) key: 属性名
// Either a valid cache is found, or will be created.
// New caches will be created and the unlock returned,
// allowing direct access to the newly created
// empty data object. A valid owner object must be provided.
var cache = this.cache[ this.key( owner ) ]; // owner的缓存对象
return key === undefined ? cache : cache[ key ]; // 没指定key的话就返回整个缓存对象,若指定了key则返回在该缓存对象的key属性的值
},
access: function( owner, key, value ) {
var stored;
// In cases where either:
//
// 1. No key was specified 没有指定key
// 2. A string key was specified, but no value provided 指定了字符串格式的key,但没有指定value
//
// Take the "read" path and allow the get method to determine
// which value to return, respectively either:
//
// 1. The entire cache object 整个缓存对象
// 2. The data stored at the key 缓存对象中某个键的值
//
if ( key === undefined || // 没有指定key或者指定了字符串格式的key,但没有指定value
((key && typeof key === "string") && value === undefined) ) {
// 没有指定key:获取整个缓存对象
// 指定了字符串格式的key,但没有指定value: 获取缓存对象中key的值
stored = this.get( owner, key );
return stored !== undefined ?
stored : this.get( owner, jQuery.camelCase(key) );
}
// [*]When the key is not a string, or both a key and value
// are specified, set or extend (existing objects) with either:
// 当key不是一个字符串,或者key和value都指定了,就会根据情况进行设置或者扩展
//
// 1. An object of properties
// 2. A key and value
//
this.set( owner, key, value );
// Since the "set" path can have two possible entry points
// return the expected data based on which path was taken[*]
return value !== undefined ? value : key;
},
remove: function( owner, key ) {
// 清空owner对应的缓存对象,或者移除缓存对象中的某个键值对
var i, name, camel,
unlock = this.key( owner ),
cache = this.cache[ unlock ];
// 如果没有指定key,则清空缓存对象
if ( key === undefined ) {
this.cache[ unlock ] = {};
} else {
// Support array or space separated string of keys
if ( jQuery.isArray( key ) ) {
// If "name" is an array of keys...
// When data is initially created, via ("key", "val") signature,
// keys will be converted to camelCase.
// Since there is no way to tell _how_ a key was added, remove
// both plain key and camelCase key. #12786
// This will only penalize the array argument path.
name = key.concat( key.map( jQuery.camelCase ) );
} else {
camel = jQuery.camelCase( key );
// Try the string as a key before any manipulation
if ( key in cache ) {
name = [ key, camel ];
} else {
// If a key with the spaces exists, use it.
// Otherwise, create an array by matching non-whitespace
name = camel;
name = name in cache ?
[ name ] : ( name.match( rnotwhite ) || [] );
}
}
i = name.length;
while ( i-- ) {
delete cache[ name[ i ] ];
}
}
},
hasData: function( owner ) {
// 检查owner在该缓存池中是否存在缓存对象
return !jQuery.isEmptyObject(
this.cache[ owner[ this.expando ] ] || {}
);
},
discard: function( owner ) {
if ( owner[ this.expando ] ) {
delete this.cache[ owner[ this.expando ] ];
}
}
};
return Data;
});
可能会有同学问道:如果我想对dataPriv进行操作该如何?
请看源码:
jQuery.extend({
hasData: function( elem ) {
return dataUser.hasData( elem ) || dataPriv.hasData( elem );
},
data: function( elem, name, data ) {
return dataUser.access( elem, name, data );
},
removeData: function( elem, name ) {
dataUser.remove( elem, name );
},
// TODO: Now that all calls to _data and _removeData have been replaced
// with direct calls to dataPriv methods, these can be deprecated.
_data: function( elem, name, data ) {
return dataPriv.access( elem, name, data );
},
_removeData: function( elem, name ) {
dataPriv.remove( elem, name );
}
});
通过源码,我们可以看出:
jQuery.data() jQuery.remove()都是对dataUser进行操作,而jQuery._data() jQuery._remove()都是对dataPriv进行操作。
理解jQuery.data(ele,name,data) 与 jQuery().data(key,value)的不同。
通过上面的源码,我们可以看到jQuery.data(ele,name,data)是对ele元素附加数据。
而jQuery().data(key,value)则会为jQuery对象中的所有DOM对象分别附加数据
来看源码(删减了部分):
jQuery.fn.extend({
data: function( key, value ) {
var i, name, data,
elem = this[ 0 ],
attrs = elem && elem.attributes;return access( this, function( value ) {
var data,
camelKey = jQuery.camelCase( key );
// 从这里可以看出,为jQuery对象中的每个DOM元素分别附加数据
this.each(function() {
// First, attempt to store a copy or reference of any
// data that might've been store with a camelCased key.
var data = dataUser.get( this, camelKey );
// For HTML5 data-* attribute interop, we have to
// store property names with dashes in a camelCase form.
// This might not apply to all properties...*
dataUser.set( this, camelKey, value );
// *... In the case of properties that might _actually_
// have dashes, we need to also store a copy of that
// unchanged property.
if ( key.indexOf("-") !== -1 && data !== undefined ) {
dataUser.set( this, key, value );
}
});
}, null, value, arguments.length > 1, null, true );
},
removeData: function( key ) {
return this.each(function() {
dataUser.remove( this, key );
});
}
});
上文中的所有源码:为jQuery.1.12
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者动作能带来一定的帮助,如果有疑问大家可以留言交流。
# jquery中的data方法
# jquery中data方法
# jquery
# data
# 深入理解jQuery.data() 的实现方式
# jQuery $.data()方法使用注意细节
# 详谈$.data()的用法和作用
# 池中
# 是一个
# 都是
# 象中
# 这就是
# 就会
# 创建一个
# 清空
# 多个
# 有一个
# 如果没有
# 不存在
# 可以看出
# 当我们
# 键值
# 是否存在
# 这时候
# 有什么
# 都有
# 来了
相关文章:
红河网站制作公司,红河事业单位身份证如何上传?
香港服务器网站卡顿?如何解决网络延迟与负载问题?
微信小程序制作网站有哪些,微信小程序需要做网站吗?
,石家庄四十八中学官网?
Android使用GridView实现日历的简单功能
ui设计制作网站有哪些,手机UI设计网址吗?
php8.4新语法match怎么用_php8.4match表达式替代switch【方法】
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
如何快速生成凡客建站的专业级图册?
C#怎么使用委托和事件 C# delegate与event编程方法
专业网站建设制作报价,网页设计制作要考什么证?
文字头像制作网站推荐软件,醒图能自动配文字吗?
建站之星2.7模板:企业网站建设与h5定制设计专题
如何在IIS中新建站点并解决端口绑定冲突?
如何获取上海专业网站定制建站电话?
相册网站制作软件,图片上的网址怎么复制?
如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?
如何使用Golang table-driven基准测试_多组数据测量函数效率
南京做网站制作公司,南京哈发网络有限公司,公司怎么样,做网页美工DIV+CSS待遇怎么样?
免费公司网站制作软件,如何申请免费主页空间做自己的网站?
电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?
建站主机是否等同于虚拟主机?
Python如何创建带属性的XML节点
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
如何通过网站建站时间优化SEO与用户体验?
存储型VPS适合搭建中小型网站吗?
黑客如何通过漏洞一步步攻陷网站服务器?
如何通过.red域名打造高辨识度品牌网站?
如何用已有域名快速搭建网站?
如何快速搭建高效可靠的建站解决方案?
建站之星在线版空间:自助建站+智能模板一键生成方案
非常酷的网站设计制作软件,酷培ai教育官方网站?
建站主机与服务器功能差异如何区分?
平台云上自主建站:模板化设计与智能工具打造高效网站
建站之星如何配置系统实现高效建站?
建站之星如何助力企业快速打造五合一网站?
建站主机默认首页配置指南:核心功能与访问路径优化
如何选择最佳自助建站系统?快速指南解析优劣
定制建站流程步骤详解:一站式方案设计与开发指南
建站之星免费版是否永久可用?
贸易公司网站制作流程,出口贸易网站设计怎么做?
c++23 std::expected怎么用 c++优雅处理函数错误返回【详解】
如何在服务器上三步完成建站并提升流量?
如何快速登录WAP自助建站平台?
宝塔新建站点为何无法访问?如何排查?
建站10G流量真的够用吗?如何应对访问高峰?
Android自定义控件实现温度旋转按钮效果
网站制作免费,什么网站能看正片电影?
建站之星如何优化SEO以实现高效排名?
建站IDE高效指南:快速搭建+SEO优化+自适应模板全解析
*请认真填写需求信息,我们会在24小时内与您取得联系。