您好,欢迎访问一九零五行业门户网

jQuery中data操作的方法及jQuery的定义

这篇文章给大家介绍的内容是关于jquery中data操作的方法及jquery的定义,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
jquery中有两个关于data操作的方法
$().data()$.data(elem);
内部其实现均离不开自定义类data
内部类 datadata在src/data/data.js定义,构建时为实例添加expando属性,作为唯一标识
function data() {    this.expando = jquery.expando + data.uid++;}
在原型上添加了多个方法
data.prototype = {    cache: function(){        ...    },    set: function(){        ...    },    get: function(){        ...    },    access: function(){        ...    },    remove: function(){        ...    },    hasdata: function(){        ...    }}
在jq内部,使用cache方法获取缓存的数据。传入一个参数owner,表示要获取缓存数据的对象。判断在owner上是否有expando属性,如果没有,说明这个owner是否第一次调用,需要在其初始化缓存数据对象。判断节点的类型,如果是元素节点或者document节点或者对象时,可以设置缓存数据。如果是元素节点或者document节点,直接使用对象字面量进行赋值,属性名是expando,值为空对象。如果是对象的话,使用object.defineproperty为其定义数据,属性名也是expando,初始化为{},同时属性描述符可以更改,不可枚举。
data.prototype.cache    cache: function( owner ) {        // check if the owner object already has a cache        // 获取在owner的缓存值        var value = owner[ this.expando ];        // if not, create one        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.            // 判断owener类型 是否能在其上调用data            // 在元素节点或body或对象上可以设置data            // 其他节点不设置缓存数据            if ( acceptdata( owner ) ) {                // if it is a node unlikely to be stringify-ed or looped over                // use plain assignment                // 此处为owner添加属性 key为data对象的expando值 建立owner和data对象之间的连接                // owner是元素节点或body                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                // owner是对象                // 为owner添加expando属性 初始化为{},同时属性描述符可以更改,不可枚举                } else {                    object.defineproperty( owner, this.expando, {                        value: value,                        configurable: true                    } );                }            }        }        return value;    }
使用set来更新缓存对象,分为data(key,value)或data(obj)两种调用情况,保存时要将键名保存为驼峰命名法。
data.prototype.set    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[ jquery.camelcase( data ) ] = value;        // handle: [ owner, { properties } ] args        } else {            // copy the properties one-by-one to the cache object            for ( prop in data ) {                cache[ jquery.camelcase( prop ) ] = data[ prop ];            }        }        return cache;    }
使用get来获取缓存对象,调用时有data(key)和data()。未指定key时直接返回整个cache对象,否则返回cache[key]。键名也要转为驼峰命名。
data.prototype.get    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 ) ];    }
对调用的方式进行区分,内部调用 set或get
通过参数的数量和类型进行区分:
key为空时,获取整个cache对象
key类型为string且value===undefined 对应获取指定值
其他调用均为set,在set内部进行区分
data.prototype.access    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        //        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        //        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来删除缓存对象属性,调用时,可以传入一个string,表示要删除的键名,或者传入一个保存多个键名的string数组。键名也要转为驼峰命名。如果不传入出参数,则直接删除掉在owner上的缓存数据对象。
data.prototype.remove    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 ( array.isarray( key ) ) {                // if key is an array of keys...                // we always set camelcase keys, so remove that.                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( rnothtmlwhite ) || [] );            }            i = key.length;            while ( i-- ) {                delete cache[ key[ i ] ];            }        }        // remove the expando if there's no more data        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 ]; } } }
判断owner上是否有缓存数据。
data.prototype.hasdata hasdata: function( owner ) { var cache = owner[ this.expando ]; return cache !== undefined && !jquery.isemptyobject( cache ); }
jquery方法的定义
定义后内部类data后,在/src/data.js进行拓展。在jquery添加了hasdata、data、 removedata、_data、_removedata等方法,在jquery.fn上添加了data和removedata方法。
在jquery拓展的方法,都是对data方法的封装,在调用时$.data()时,并无对set和get操作区分,在data.prototype.access内部区分set和get。下面源码中,datauser和datapriv是data实例,分别为缓存数据和表示jq对象是否将元素的data属性添加到datauser中
// $.datajquery.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.fn上拓展的方法只有data和removedata。在data内,先对$().data()和$().data({k:v})两个调用情况进行处理。如果是第一种情况,则返回在this[0]上的缓存数据对象,如果是第一次以$().data()的方式调用,同时还会将元素上的data属性添加datauser中,并更新datapriv。如果是$().data({k:v})的调用方式,则遍历jq对象,为每个节点更新缓存数据。其他调用方式如$().data(k)和$().data(k,v)则调用access进行处理。此处的access并非data.prototype.access。
removedata则遍历jq对象,删除在每个节点上的缓存数据。
// $().datajquery.fn.extend( { data: function( key, value ) { var i, name, data, elem = this[ 0 ], // elem为dom对象 attrs = elem && elem.attributes; // 节点上的属性 // gets all values // $().data() if ( key === undefined ) { if ( this.length ) { data = datauser.get( elem ); // elem是元素节点,且datapriv中无hasdataattrs时执行这个代码块里的代码 // datapriv上的hasdataattrs表示elem是否有data-xxx属性 // 初始化datapriv后花括号内的代码不再执行,即以下的if内的代码只执行一次 if ( elem.nodetype === 1 && !datapriv.get( elem, "hasdataattrs" ) ) { i = attrs.length; while ( i-- ) { // support: ie 11 only // the attrs elements can be null (#14894) // 将elem的data-*-*属性以*-*转为驼峰命名方式的值为键 // 在dataattr函数内保存到datauser中 // 所以用$().data可以获取元素的data-*属性 但修改后dom上的属性却不变化 if ( attrs[ i ] ) { name = attrs[ i ].name; // name为data-xxx if ( name.indexof( "data-" ) === 0 ) { // name为xxx name = jquery.camelcase( name.slice( 5 ) ); dataattr( elem, name, data[ name ] ); } } } // 同时将datapriv的hasdataattrs属性设置为真,表示已经将元素属性节点上的data属性保存到缓存对象中 datapriv.set( elem, "hasdataattrs", true ); } } return data; } // sets multiple values // $().data(obj) 此处遍历this,即遍历jq对象上所有的节点,并在其设置值 if ( typeof key === "object" ) { return this.each( function() { datauser.set( this, key ); } ); } // 除了$().data()和$().data({k:v})的其他情况 return access( this, function( value ) { var data; // the calling jquery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the // `value` parameter was not undefined. an empty jquery object // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. // value undefined说明是获取操作 // 调用$().data(k) if ( elem && value === undefined ) { // attempt to get data from the cache // the key will always be camelcased in data // 从datauser中获取 非undefined时返回 data = datauser.get( elem, key ); if ( data !== undefined ) { return data; } // attempt to "discover" the data in // html5 custom data-* attrs // datauser中不存在key,调用dataattr查找元素的data-*属性 // 如果存在属性,更新datauser并返回其值 data = dataattr( elem, key ); if ( data !== undefined ) { return data; } // we tried really hard, but the data doesn't exist. return; } // set the data... // jq对象长度 >= 1, 调用如$().data(k,v) 遍历jq对象,为每个节点设置缓存数据            this.each( function() {                // we always store the camelcased key                datauser.set( this, key, value );            } );        }, null, value, arguments.length > 1, null, true );    },    // 遍历jq对象,删除各个元素上的缓存数据    removedata: function( key ) {        return this.each( function() {            datauser.remove( this, key );        } );    }} );
其中,getdata用于对元素上的data属性进行类型转换,dataattr用于获取保存在元素节点上的data属性,并同时更新datauser。需要注意的是,以$().data(k, v)方式调用时,如果在缓存数据上查找不到属性,则会调用dataattr在元素查找属性。
// 属性值是string 进行类型转换function getdata( data ) {    if ( data === true ) {        return true;    }    if ( data === false ) {        return false;    }    if ( data === null ) {        return null;    }    // only convert to a number if it doesn't change the string    // data转化成number再转成string后仍严格等于data    if ( data === +data +  ) {        return +data;    }    if ( rbrace.test( data ) ) {        return json.parse( data );    }    return data;}// 获取元素的dataset中的属性,并保存到datauser中function dataattr( elem, key, data ) {    var name;    // if nothing was found internally, try to fetch any    // data from the html5 data-* attribute    // 此处获取dataset里的值    if ( data === undefined && elem.nodetype === 1 ) {        name = data- + key.replace( rmultidash, -$& ).tolowercase(); // 此处将驼峰命名方式的key转化为data-*-*        data = elem.getattribute( name );        if ( typeof data === string ) {            try {                data = getdata( data );            } catch ( e ) {}            // make sure we set the data so it isn't changed later            // 将元素的data-*属性保存到datauser中            datauser.set( elem, key, data );        } else {            data = undefined;        }    }    return data;}
相关文章推荐:
angular表单验证的两种方法介绍
javascript函数怎么用?javascript函数的属性和方法的介绍
以上就是jquery中data操作的方法及jquery的定义的详细内容。
其它类似信息

推荐信息