五、数据缓存Data3——.removeData(key, value)、.removeData(key)

// 代码行: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指向存储数据得对象,对于DOM元素,数据存储在全局缓存对象jQuery.cache中,对于JavaScript对象,数据则直接存储在JavaScript对象上。
            cache = owner[ this.expando ];
        // 如果数据缓存对象cache不存在,则直接返回。
        if ( cache === undefined ) {
            return;
        }

        // 如果key存在,即有待移除得选项
        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 );
                // 如果参数key不是数组,则将其封装或解析成为数组
            } 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;

            // 遍历参数name中得数据名,用运算符delete逐个从数据缓存对象cache中移除。
            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)
            // 删除扩展得jQuery.expando属性
            // Webkit和Blink在删除DOM节点属性时会影响性能,因此将其设置为undefined
            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( {
    // 代码行:4232——4234
    // 方法jQuery.removeData()用于移除通过jquery.data()设置得数据,通过调用dataUser.remove(elem, name)实现。
    removeData: function( elem, name ) {
        // 参数elem:待移除数据的DOM元素或JavaScript对象。
        // 参数name:待移除的数据名,可以时单个数据名、数据名数组、用空格分隔得多个数据名。
        dataUser.remove( elem, name );
    },

    _removeData: function( elem, name ) {
        dataPriv.remove( elem, name );
    }
} );

// 代码行:4247——4328
jQuery.fn.extend( {
    // 代码行:4323——4327
    // 方法.removeData(key)用于移除匹配元素得自定义数据,通过在每个匹配元素上调用方法dataUser.remove()实现。
    removeData: function( key ) {
        return this.each( function() {
            dataUser.remove( this, key );
        } );
    }
} );

 

posted @ 2019-05-30 14:57  道鼎金刚  阅读(285)  评论(0)    收藏  举报