五、数据缓存Data2——jQuery.data( elem, name, data )、jQuery._data(elem, name, data)

实际代码:

// 代码行:4004——4158

function Data() {
    // 设定唯一标识
    this.expando = jQuery.expando + Data.uid++;
}

Data.uid = 1;

Data.prototype = {

    // 建立一个cache
    cache: function( owner ) {

        // Check if the owner object already has a cache
        // 检查所有者对象是否已经拥有缓存
        var value = owner[ this.expando ];

        // If not, create one
        // 如果没有value,则创建一个
        if ( !value ) {
            value = {};

            // We can accept data for non-element nodes in modern browsers,
            // but we should not, see #8335.
            // 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是一个合格者后
                if ( owner.nodeType ) {
                    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
                //否则,将其保护在一个不可枚举的属性中
                //可配置的必须为true才能允许属性为true  
                //删除数据时删除
                } else {
                    Object.defineProperty( owner, this.expando, {
                        value: value,
                        configurable: true
                    } );
                }
            }
        }

        return value;
    },
    // set()用于dom设置key和value
    set: function( owner, data, value ) {
        var prop,
            cache = this.cache( owner );

        // Handle: [ owner, key, value ] args
        // Always use camelCase key (gh-2257)
        if ( typeof data === "string" ) {
            cache[ camelCase( data ) ] = value;

        // Handle: [ owner, { properties } ] args
        // 处理data为这种情况:[ owner, { properties } ]
        } else {

            // Copy the properties one-by-one to the cache object
            // 将属性逐个复制到缓存对象
            for ( prop in data ) {
                cache[ camelCase( prop ) ] = data[ prop ];
            }
        }
        return cache;
    },
    get: function( owner, key ) {
        return key === undefined ?
            this.cache( owner ) :

            // Always use camelCase key (gh-2257)
            owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
    },
    // 用来访问,将get、set结合到一起,并对underfined判断
    access: function( owner, key, value ) {

        // In cases where either:
        //
        //   1. No key was specified
        //   2. A string key was specified, but no value provided
        //
        // 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
        //
        //在下列任何一种情况下:1.没有指定密钥。2.指定了字符串键,但没有提供值。选择“read”路径并允许get方法确定,分别返回哪个值:1.整个缓存对象 2.存储在键上的数据
        // 如果key是undefined或key是字符串、data是undefined说明实在读取数据
        if ( key === undefined ||
                ( ( key && typeof key === "string" ) && value === undefined ) ) {

            return this.get( owner, key );
        }

        // When the key is not a string, or both a key and value
        // are specified, set or extend (existing objects) with either:
        //
        //   1. An object of properties
        //   2. A key and value
        //
        //当键不是字符串,或者键和值都不是时。指定、设置或扩展(现有对象)时,1.属性的对象。2.键和值
        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[*]
        // 因为“set”路径可以有两个可能的入口点
        // 返回所选择路径的期望数据[*]
        return value !== undefined ? value : key;
    },
    // 用于移除cache
    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
            // 支持删除数组格式的key
            if ( Array.isArray( key ) ) {

                // If key is an array of keys...
                // We always set camelCase keys, so remove that.
                key = key.map( camelCase );
            } else {
                // 为了保持一致,强行的构造了一个数组
                key = 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( rnothtmlwhite ) || [] );
            }

            i = key.length;

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

        // Remove the expando if there's no more data
        // cache为空的时候,删除整个缓存 
        if ( key === undefined || jQuery.isEmptyObject( cache ) ) {

            // Support: Chrome <=35 - 45
            // Webkit & Blink performance suffers when deleting properties
            // from DOM nodes, so set to undefined instead
            // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
            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 dataPriv = new Data();

var dataUser = new Data();


jQuery.extend( {
    // 代码行:4228——4230
    // 方法jQuery.data()用于为DOM元素或JavaScript对象设置任意类型的数据,或返回指定名称的数据,或返回关联的数据缓存对象。通过调用dataUser.access(elem, name, data)
    data: function( elem, name, data ) {
        // 参数elem:表示与数据关联的DOM元素。
        // 参数name:表示要设置或读取的数据名,或者时含有键值对的对象。
        // 参数data:表示要设置的数据值,可以时任意类型。
        return dataUser.access( elem, name, data );
    },
    // 代码行:4238——4240
    // TODO: Now that all calls to _data and _removeData have been replaced
    // with direct calls to dataPriv methods, these can be deprecated.
    // 方法jQuery._data(elem, name, data )用于为DOM元素或JavaScript对象设置或读取内部数据,通过调用方法dataPriv.access(elem, name, data)实现
    // 在jQuery内部,方法jQuery._data(elem, name, data)用于为队列模块、动画模块、样式操作模块、事件系统提供基础功能,负责设置或读取这些模块运行时的内部数据。
    _data: function( elem, name, data ) {
        return dataPriv.access( elem, name, data );
    }
} );

 

posted @ 2019-05-29 13:55  道鼎金刚  阅读(290)  评论(0)    收藏  举报