data()方法
jQuery.data() 方法向被选元素储存数据,或者从被选元素获取数据
$(".box").data("key", "hello") //储存数据
console.log($(".box").data("key")) //获取数据,打印hello
data()方法在dom元素存储数据,并不是直接将数据绑定到dom元素上,dom元素常驻于内存当中,不会被销毁(除非关页面),如果在dom元素上绑定大量数据,势必会导致内存泄漏。那么jQuer如何缓存数据呢?

- dom元素生成一个uuid属性,值就是ID,dom[uuid] = ID
- UUID = expando,expando是jQuery内部生成随机数方法,expando="jQuery" + (Math.random()).replace(/\D/g, "")
- jQuery 内部 Data 对象会创建一个 Cache 对象用于储存数据,key 对应 ID,value 对应数据, Cache = { ID : { //数据 }}
通过这种方式,实现数据跟 dom 的绑定,数据是储存于 Cache,而不是 dom 元素上
Data对象
jQuer内部的Data对象,主要有三个方法,get、key、以及set,核心方法是key方法,key的作用主要是根据 dom[UUID] 返回 Cache 中的 ID,如果dom没有UUID属性,则在dom上添加UUID属性,并将Cache添加ID属性,值为空
function Data(){
this.expando = jQuery.expando + Math.random()
this.cache = {}
}
Data.uid = 1
//创建缓存及返回
Data.prototype = {
//key方法,获取ID
//同时在this.cache里面建立一个 uid: {}
key(elem){
var descriptor = {},
unlock = elem[this.expando]
if(!unlock){
unlock = Data.uid++
descriptor[this.expando] = {
value: unlock
}
/*
Dom扩展属性,相当于
elem[this.expando] = unlock
*/
Object.defineProperties(elem, descriptor)
}
if(!this.cache[unlock]){
this.cache[unlock] = {}
}
return unlock
},
get(elem, key){
//找到或者创建缓存
var cache = this.cache[this.key(elem)]
//key 有值直接在缓存中读取
return key === undefined ? cache : cache[key]
},
set(owner, key, value){
var unlock = this.key(owner),
cache = this.cache[unlock],
prop
if(typeof key === 'string'){
cache[key] = value
}
//如果key是一个对象
if(jQuery.isPlainObject(key)){
for( prop in key ){
cache[prop] = key[prop]
}
}
}
}
data()方法的实现
//缓存内部数据
var data_user = new Data(); //创建Data对象
data(key, value){
var _this = this //this代表$(".box")
return access(this, function(key, value){
if(value === undefined){ //获取数据
var data = data_user.get(this, key)
if (data!==undefined) {
return data
}
}
_this.each(function(){
data_user.set(this, key, value) //在data_user上储存数据并在获取的dom上添加属性UUID
})
}, key, value)
},
access: function(elems, func, key, value){
var len = elems.length
var testting = key === null
var cache
if(value !== undefined){
//说明value有值,则做set操作
if(testting){
cache = func
func = function(key, value){
cache.call(this, key, value)
}
}
for(var i = 0; i < len; i++){
func.call(elems[i], key, value)
}
}
return func.call(elems[0], key, value)
},
队列queue
queue() 方法是基于data()实现的,它是显示或操作在匹配元素上执行的函数队列,通常与 dequeue() 方法一起使用
var box = $('box')
function fn1(){
console.log('这是方法1')
}
function fn2(){
console.log('这是方法2')
}
//给dom元素box上存储名为first的函数队列
jQuery.queue(box, "first", fn1) //将fn1添加到first函数队列
jQuery.queue(box, "first", fn2) //将fn2添加到first函数队列
console.log(jQuery.queue(box, "first")) //打印包含fn1及fn2的函数数组:[fn,fn]
//执行队列
jQuery.dequeue(box, "first") //打印:这是方法1
jQuery.dequeue(box, "first") //打印:这是方法2
实现
//缓存内部数据
var data_user = new Data(); //创建Data对象
queue(elem, type, data){
var queue
if(elem){
type = type + "queue" //firstqueue
queue = data_user.get(elem, type) //获取Cache里的缓存数据
if(data){
if(!queue){
//由于queue储存的是函数队列,jQuery.markArray()方法是将传入的数据变成数组[data]
data_user.set(elem, type, jQuery.markArray(data))
} else {
queue.push(data)
}
}
return queue
}
},
dequeue(elem, type){
type = type || "fx"
var queue = jQuery.queue(elem, type),
next = function(){
jQuery.dequeue(elem, type)
},
fn = queue.shift()
fn.call(elem, next)
}
next()
在 dequeue() 方法中有一个 next() 方法,其本身就是 dequeue() 方法。它会在函数中传入 next 参数,用于继续执行函数队列,相当于再次执行 jQuery.dequeue() 方法
var box = $('box')
function fn1(next){
console.log('这是方法1')
next() //继续执行fn2方法,打印:这是方法2
}
function fn2(){
console.log('这是方法2')
}
jQuery.queue(box, "first", fn1)
jQuery.queue(box, "first", fn2)
//执行队列
jQuery.dequeue(box, "first") //打印:这是方法1