jquery源码分析—data缓存

本文介绍了jQuery中的data()方法,详细解析了其工作原理及如何避免内存泄漏。探讨了data()方法的不同使用方式,包括设置、获取和删除数据,并深入分析了jQuery 3.0.0版本中data()方法的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

data和attr、prop的作用类似 都是给元素添加属性,但是data可以防止DOM元素与对象之间的互相引用,从而防止出现内存泄漏的现象。

data的使用方法

data可以作为工具方法和实例方法使用

var obj = {}; 
$.data(obj,'name','hello');
$.removeData(obj,'name');
console.log($.data(obj))

$('#div1').data('name','hello');//设置
console.log($('#div1').data('name'));//获取
$('#div1').removeData('name')

data的原理

为了避免内存泄漏 data采用间接为元素添加属性的方法实现 data添加元素属性并不是添加到元素上,而是添加到了一个json数据中,通过在元素上添加一个唯一属性,让该属性与json数组建立联系。
这里写图片描述

jquery的最新版本(3.0.0)与以往的思想不同。 在该版本中,data添加属性时 将json直接赋值给了唯一属性名。这种方式如何避免内存泄漏,还未想明白

data源码分析

源码中有一个Data类(3.0.0),工具方法和实例方法都是基于这个Data类实现的,我们先看一下该类的实现

var acceptData = function( owner ) {

// Accepts only:
//  - Node
//    - Node.ELEMENT_NODE
//    - Node.DOCUMENT_NODE
//  - Object
//    - Any
/* jshint -W018 */
//-----------------当owner为字符串 也返回true????????????
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
};

function Data() { 
// jQuery.expando jquery的版本加随机数
this.expando = jQuery.expando + Data.uid++; //唯一标示,表示data添加到元素中的属性名

}

Data.uid = 1;

Data.prototype = {
//给owner添加属性 owner可以为元素 对象
cache: function( owner ) {

    // Check if the owner object already has a cache
    // 检查元素中是否有该属性 如果没有就创建
    var value = owner[ this.expando ];

    // If not, create one
    if ( !value ) {
        value = {};

        // We can accept data for non-element nodes in modern browsers,
        // Always return an empty object.
        if ( acceptData( owner ) ) {

            // If it is a node unlikely to be stringify-ed or looped over
            // use plain assignment
            // 如果owner为文档节点 给owner赋值
            if ( owner.nodeType ) {
                //将owner[ this.expando ]赋值 
                owner[ this.expando ] = value;

            // Otherwise secure it in a non-enumerable property
            // configurable must be true to allow the property to be
            // deleted when data is removed
            } else {
                //如果不存在就创建 这种方法创建的属性是不能被修改的
                //object.defineProperty()方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象
                Object.defineProperty( owner, this.expando, {
                    value: value,
                    configurable: true//表示能否把属性修改为访问器属性 能否通过delete删除属性
                } );
            }
        }
    }

    return value;
},

//设置cache的值
set: function( owner, data, value ) {
    var prop,
        cache = this.cache( owner );
        console.log(cache);

    // Handle: [ owner, key, value ] args
    // Always use camelCase key (gh-2257)
    if ( typeof data === "string" ) {
        //给cache添加属性和属性值
        cache[ jQuery.camelCase( data ) ] = value;

    // Handle: [ owner, { properties } ] args
    } else {

        // Copy the properties one-by-one to the cache object
        // 若data为json 将json中的数据拷贝到cache中
        for ( prop in data ) {
            cache[ jQuery.camelCase( prop ) ] = data[ prop ];
        }
    }
    return cache;
},
//获得cache中的属性值 若key为undefined 返回所有属性
get: function( owner, key ) {
    return key === undefined ?
        this.cache( owner ) :
        // Always use camelCase key (gh-2257)
        owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
},

//合并get方法和set方法
access: function( owner, key, value ) {
    //若key未定义或key为字符串 value未定义 调用get方法 获取属性值
    if ( key === undefined ||
            ( ( key && typeof key === "string" ) && value === undefined ) ) {

        return this.get( owner, key );
    }


    this.set( owner, key, value );

    return value !== undefined ? value : key;
},

remove: function( owner, key ) {
    var i,
        cache = owner[ this.expando ];

    if ( cache === undefined ) {
        return;
    }

    if ( key !== undefined ) {

        // Support array or space separated string of keys
        // 判断删除的可以是不是数组 若为数字 则同时删除数组中的所有项
        if ( jQuery.isArray( key ) ) {

            // 返回驼峰写法
            key = key.map( jQuery.camelCase );
        } else {
            key = jQuery.camelCase( key );

            // If a key with the spaces exists, use it.
            // Otherwise, create an array by matching non-whitespace
            key = key in cache ?
                [ key ] :
                ( key.match( rnotwhite ) || [] );
        }

        i = key.length;

        while ( i-- ) {
            delete cache[ key[ i ] ];
        }
    }

    // Remove the expando if there's no more data
    // 当key不存在时 清空cache
    if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
        if ( owner.nodeType ) {
            owner[ this.expando ] = undefined;
        } else {
            delete owner[ this.expando ];
        }
    }
},
hasData: function( owner ) {
    var cache = owner[ this.expando ];
    return cache !== undefined && !jQuery.isEmptyObject( cache );
}
};

var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,//匹配json和数组
rmultiDash = /[A-Z]/g;
//该函数完成h5中的"data—"格式的属性值
function dataAttr( elem, key, data ) {
var name;

// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
// 当data属性名不存在时 将寻找h5中的data-属性
if ( data === undefined && elem.nodeType === 1 ) {
    name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
    data = elem.getAttribute( name );

    if ( typeof data === "string" ) {
        try {

            //将字符串类型的值转换为特定类型的值
            data = data === "true" ? true :
                data === "false" ? false :
                data === "null" ? null :

                // Only convert to a number if it doesn't change the string
                //判断是否为数值字符串 如果是数值字符串 将该字符串转换为数值类型
                +data + "" === data ? +data :
                //判断字符串中的值是否为json或数组 如果是 将其转换为json或数组
                rbrace.test( data ) ? JSON.parse( data ) :
                data;
        } catch ( e ) {}

        // Make sure we set the data so it isn't changed later
        dataUser.set( elem, key, data );
    } else {
        data = undefined;
    }
}
return data;
}

data的工具方法和实例方法基本上都是对该类的调用 很容易理解 这里不再详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值