详解jquery中的大图|详解jQuery中的data()

时间:2020-12-15  来源:jquery  阅读:

data有什么作用?

在我们平时js编码过程中,我们经常会向DOM元素中添加各种自定义属性,这样有一个弊端。

  1、假设我们在DOM元素中添加了一个属性,这个属性指向了某个js对象。dom1.ele = jsObj

  2、当这个js对象发挥完作用后,我们已经用不到他了。这时候按理说应该把这个js变量清空,释放内存。大家都知道,如果一个js对象不存在任何外在引用的话,解释器会自动将其在内存中删除,这也是javascript相对于c++等手动管理内存的程序的优点。

  3、但是这时候问题来了,因为DOM元素引用了这个js对象,尽管这个js对象已经没有存在的意义了,但是解释器是不会把他删除的。如果想要把其删除,我们可能需要将DOM元素的这个属性设置为null。

  4、我们编写了这么多的代码,哪里能把 每个js对象是不是被DOM元素引用了都记住啊?

  5、而且,假如DOM元素与js对象之间相互循环引用,根本就无法删除! 这就是内存泄漏

  6、所以,为了避免这种情况的发生,我们要尽量避免 引用数据(这里的引用数据可以说是javascript对象) 直接依附在DOM对象上。

  7、data就是用来搞定以上问题的方法。

data是如何搞定以上问题的?

首先来说一说jQuery中Data实现的大体思路:

  1、首先我们创建一个数据缓存池,这个缓存池专门用来存储  向 DOM对象或者jQuery对象附加的额外数据。

  2、当我们要向DOM对象或者jQuery对象附加额外数据的时候,我们附加的数据其实是保存于这个缓存池中

  3、DOM对象或者jQuery对象生成一个额外属性,这个属性保存了 附加数据在缓存池中的‘门牌号"(位置或者索引)

  4、当我们访问DOM对象或者jQuery对象的附加数据时,实际上是先取得其附加数据的门牌号,然后找到缓存池中对应门牌号的数据,进行操作。

大体思路讲完,那么来分析一下具体思路:

在jQuery中,有一个Data构造函数,每当运行这个构造函数时,就会生成一个实例。

jQuery默认会自动生成两个Data实例:

  var dataPriv = new Data()  jQuery私有的,我们尽量不要对这个实例进行操作。

  var dataUser = new Data()  这个就是服务于用户了,我们使用data()方法都是对这个实例进行操作。

所有的Data实例都有以下属性:

  expando:  值为字符串类型,每个Data实例的expando属性的值都不相同,用来区分不同的Data实例,类似于id的作用,expando的值就是上文中的额外属性。

  uid:   这就是上文中的门牌号,初始为1,随着不同对象的附加数据的加入,自增长。

  cache : 一个对象 {} ,这就是缓存池了。

来个实例:

$(document.body).data("aaa","value-aaa") console.dir(document.body)

body对象有一个名为jquer210023......的额外属性,

  这个属性的名称就是dataUser的expando的值

  这个属性的值就是门牌号。

总结:data实际上就是对js对象或者DOM对象的额外属性做了一个集中的管理。对于那些不会产生内存泄漏的额外数据,我们也可以直接向js对象或者DOM对象附加。

好,理清楚上面的关系后,我们再来看一下源码:

define([  "../core",  "../var/rnotwhite",  "./accepts" ],function( jQuery, rnotwhite ) {   functionData() {  // Support: Android<4,  // Old WebKit does not have Object.preventExtensions/freeze method,  // return new empty object instead with no [[set]] accessor  Object.defineProperty(this.cache = {}, 0, {  get:function() {   return{};  }  });  // jQuery.expando = "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ) expando是一个jQuery的唯一标示  // 格式是:"jQuery\\d*" 也就是"jQuery"+ 多个数字。这里为啥要搞得这么麻烦呢?  // 应因为我们可能会创建多个Data对象,为了保证每个Data对象的expando属性的值不相等,所以这么搞  this.expando = jQuery.expando + Math.random(); }   Data.uid = 1;// Data函数的属性,"静态属性" Data.accepts = jQuery.acceptData;   Data.prototype = {  key:function( owner ) {  // We can accept data for non-element nodes in modern browsers,  // but we should not, see #8335.  // Always return the key for a frozen object.  // 若owner在该缓存池中存在对应的缓存对象,则返回混存对象的key(是一个数字),  // 若owner在该缓存池中不存在对应的缓存对象,则在缓存池中为其创建一个缓存对象,并返回该缓存对象的key  if( !Data.accepts( owner ) ) {   return0;  }    vardescriptor = {},   // Check if the owner object already has a cache key   // 检查owner对象在该缓存池中是否存在缓存   unlock = owner[this.expando ];// 是一个数字,用来作为缓存池中缓存对象的key    // If not, create one  // 如果没有,则创建一个  if( !unlock ) {   unlock = Data.uid++;     // Secure it in a non-enumerable, non-writable property   // 给owner附加一个属性 owner[this.expando] = unlock ,并且该属性不能被枚举,   try{   descriptor[this.expando ] = { value: unlock };   Object.defineProperties( owner, descriptor );     // Support: Android<4   // Fallback to a less secure definition   }catch( e ) {   descriptor[this.expando ] = unlock;   jQuery.extend( owner, descriptor );   }  }    // Ensure the cache object  // 确保owner对应的缓存对象已存在  if( !this.cache[ unlock ] ) {   this.cache[ unlock ] = {};  }  // 返回unlock  returnunlock;  },  set:function( owner, data, value ) {  // 设置owner对应的缓存对象  varprop,   // There may be an unlock assigned to this node,   // if there is no entry for this "owner", create one inline   // and set the unlock as though an owner entry had always existed   unlock =this.key( owner ),// 获取owner的对应的缓存对象在缓存池中的key(这里的key,是键值对中的键的意思)   cache =this.cache[ unlock ];// 获取owner所对应的缓存对象    // Handle: [ owner, key, value ] args  // 根据传入参数的个数以及类型实现重载  if(typeofdata ==="string") {   cache[ data ] = value;    // Handle: [ owner, { properties } ] args  }else{   // Fresh assignments by object are shallow copied   if( jQuery.isEmptyObject( cache ) ) {   jQuery.extend(this.cache[ unlock ], data );   // Otherwise, copy the properties one-by-one to the cache object   }else{   for( propindata ) {    cache[ prop ] = data[ prop ];   }   }  }  // 返回缓存对象  returncache;  },  get:function( owner, key ) {  // 获取owner对象的名为key的属性值  // owner:是一个对象(可以是jQuery对象也可以是DOM对象) key: 属性名  // Either a valid cache is found, or will be created.  // New caches will be created and the unlock returned,  // allowing direct access to the newly created  // empty data object. A valid owner object must be provided.    varcache =this.cache[this.key( owner ) ];// owner的缓存对象    returnkey === undefined ? cache : cache[ key ];// 没指定key的话就返回整个缓存对象,若指定了key则返回在该缓存对象的key属性的值  },  access:function( owner, key, value ) {  varstored;  // In cases where either:  //  // 1. No key was specified 没有指定key  // 2. A string key was specified, but no value provided 指定了字符串格式的key,但没有指定value  //  // 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或者指定了字符串格式的key,但没有指定value   ((key &&typeofkey ==="string") && value === undefined) ) {     // 没有指定key:获取整个缓存对象   // 指定了字符串格式的key,但没有指定value: 获取缓存对象中key的值   stored =this.get( owner, key );       returnstored !== undefined ?   stored :this.get( owner, jQuery.camelCase(key) );  }    // [*]When the key is not a string, or both a key and value  // are specified, set or extend (existing objects) with either:  // 当key不是一个字符串,或者key和value都指定了,就会根据情况进行设置或者扩展  //  // 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[*]  returnvalue !== undefined ? value : key;  },  remove:function( owner, key ) {  // 清空owner对应的缓存对象,或者移除缓存对象中的某个键值对  vari, name, camel,   unlock =this.key( owner ),   cache =this.cache[ unlock ];  // 如果没有指定key,则清空缓存对象  if( key === undefined ) {   this.cache[ unlock ] = {};    }else{   // Support array or space separated string of keys   if( jQuery.isArray( key ) ) {   // If "name" is an array of keys...   // When data is initially created, via ("key", "val") signature,   // keys will be converted to camelCase.   // Since there is no way to tell _how_ a key was added, remove   // both plain key and camelCase key. #12786   // This will only penalize the array argument path.   name = key.concat( key.map( jQuery.camelCase ) );   }else{   camel = jQuery.camelCase( key );   // Try the string as a key before any manipulation   if( keyincache ) {    name = [ key, camel ];   }else{    // If a key with the spaces exists, use it.    // Otherwise, create an array by matching non-whitespace    name = camel;    name = nameincache ?    [ name ] : ( name.match( rnotwhite ) || [] );   }   }     i = name.length;   while( i-- ) {   deletecache[ name[ i ] ];   }  }  },  hasData:function( owner ) {  // 检查owner在该缓存池中是否存在缓存对象  return!jQuery.isEmptyObject(   this.cache[ owner[this.expando ] ] || {}  );  },  discard:function( owner ) {  if( owner[this.expando ] ) {   deletethis.cache[ owner[this.expando ] ];  }  } };   returnData; });

可能会有同学问道:如果我想对dataPriv进行操作该如何?

请看源码:

jQuery.extend({  hasData:function( elem ) {  returndataUser.hasData( elem ) || dataPriv.hasData( elem );  },    data:function( elem, name, data ) {  returndataUser.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 ) {  returndataPriv.access( elem, name, data );  },    _removeData:function( elem, name ) {  dataPriv.remove( elem, name );  } });

通过源码,我们可以看出:

jQuery.data() jQuery.remove()都是对dataUser进行操作,而jQuery._data() jQuery._remove()都是对dataPriv进行操作。

理解jQuery.data(ele,name,data) 与 jQuery().data(key,value)的不同。

  通过上面的源码,我们可以看到jQuery.data(ele,name,data)是对ele元素附加数据。

  而jQuery().data(key,value)则会为jQuery对象中的所有DOM对象分别附加数据

来看源码(删减了部分):

1,null,true);  },    removeData:function( key ) {  returnthis.each(function() {   dataUser.remove(this, key );  });  } });

详解jquery中的大图|详解jQuery中的data()

http://m.bbyears.com/wangyezhizuo/116645.html

推荐访问:
相关阅读 猜你喜欢
本类排行 本类最新