jQuery.data() の実装についての深い理解

黄舟
リリース: 2016-12-12 16:27:38
オリジナル
1150 人が閲覧しました

jQuery.data() は、通常のオブジェクトまたは DOM 要素にデータを添付 (および取得) するために使用されます。

以下では、その実装を 3 つの部分に分けて分析します。

1. 名前と値を使用してオブジェクトにデータを追加します。つまり、3 つのパラメータを渡します。最初のパラメータはデータを追加する必要があるオブジェクト、2 番目のパラメータはデータの名前、3 番目のパラメータは値です。データの。もちろん、値を取得するだけの場合は、3 番目のパラメーターを渡す必要はありません。

2. 別のオブジェクトを使用してオブジェクトにデータを追加します。つまり、2 つのパラメータを渡します。最初のパラメータは追加する必要があるデータ オブジェクト (「obj」と呼びます)、2 番目のパラメータもオブジェクトです (これを「obj」と呼びます)。 it "another" "); "another" に含まれるキーと値のペアがコピーされます。 データキャッシュ内の「obj」(「キャッシュ」と呼びます)。

3. DOM 要素にデータをアタッチします。DOM 要素もオブジェクトの一種ですが、IE6 と IE7 は DOM 要素に直接アタッチされます。 オブジェクトのガベージ コレクションに問題があるため、このデータをグローバル キャッシュ (「globalCache」と呼びます) に保存します。つまり、「globalCache」には複数の DOM が含まれます。 要素の「cache」を指定し、「cache」に対応する uid を格納する属性を DOM 要素に追加します。

名前と値を使用してオブジェクトにデータを追加する

jQuery.data() を使用して通常のオブジェクトにデータを追加する場合、本質はオブジェクトに「キャッシュ」を追加し、特別な属性名を使用することです。

データを格納する「キャッシュ」もオブジェクトです。「obj」に付けたデータは実際には「キャッシュ」の属性になります。そして「キャッシュ」というのは、 「obj」の属性。jQuery 1.6 では、この属性の名前は「jQuery16」に乱数を加えたものです (後述)。 "jQuery16018518865841457738" )。

次のコードを使用して jQuery.data() の機能をテストできます:

<script type="text/javascript" src="jqueryjs"></script>  
<script>  
obj = {};  
$data(obj, &#39;name&#39;, &#39;value&#39;);  
documentwrite("$data(obj, &#39;name&#39;) = " + $data(obj, &#39;name&#39;) + &#39;<br />&#39;);     
for (var key in obj) 
{  
 documentwrite("obj" + key + &#39;name = &#39; + obj[key]name);  
 }  
 </script>
ログイン後にコピー

結果は次のように表示されます:

$.data(obj, &#39;name&#39;) = value  
obj.jQuery16018518865841457738.name = value
ログイン後にコピー

このコードでは、まず「obj」に属性 (「name」という名前) を追加します。 、値は "value")、$.data(obj, 'name') を渡します。 添付データを取得します。実装メカニズムをより深く理解するために、ループを使用して「obj」の属性を取得しました。実際には、「obj」に付加されている属性を取り出しました。 「キャッシュ」オブジェクト。

ご覧のとおり、jQuery.data() は実際には「jQuery16018518865841457738」という名前のファイルに「obj」を追加します。 (名前はランダムです) オブジェクト、これが「キャッシュ」です。 jquery.data() を使用してオブジェクトに付加された属性は、実際にはこの「キャッシュ」の属性になります。

次のコードを使用して同様の関数を実現できます:

$ = function() 
{   
var expando = "jQuery" + ("6" + Mathrandom())replace(/\D/g, &#39;&#39;);      
function getData(cache, name) 
{    
return cache[name];  
 }     
function setData(cache, name, value) 
{    
cache[name] = value;   
}      
function getCache(obj) 
{    
obj[expando] = obj[expando] || {};    
return obj[expando];   
}      
return 
{    
data : function(obj, name, value) 
{     
var cache = getCache(obj);        
if (value === undefined) 
{      
return getData(cache, name);     
} else 
{      
setData(cache, name, value);     
}    
}   
}  
}();
ログイン後にコピー

関数のコードの最初の行は、「expando」、つまり「jQuery1.6」を定義しています。 乱数 (0.xxxx) を追加し、数値以外の部分を削除します。この形式は jQuery の他の場所で使用されるため、ここでは説明しません。これは特別な名前であり、さまざまなページを識別するために使用できることを知っておいてください。違うとして iframe の「expando」は異なります)。

次に、データを取得するための関数 getData() が定義されています。これは、実際には「cache」から属性を取得するもので、cache[name] を返します。

次に、「cache」のプロパティを設定するために使用される setData() 関数があります。実際には、cache[name] の値を設定します。

の後に getCache() が続き、「obj」の「キャッシュ」を取得します。つまり、obj[expando] の場合は obj[expando] です。 空の場合は初期化が行われます。

最後に、データメソッドが公開されます。まず、受信した「obj」に従って、2 つのパラメータが渡されたときに「obj」にアタッチされた「キャッシュ」を取得します。 getData() メソッド; 3 つのパラメータが渡されると、setData() メソッドが呼び出されます。

別のオブジェクトを使用してオブジェクトにデータを追加します

名前と値を指定して値を割り当てることに加えて、別のオブジェクト (「別の」) をパラメータとして直接渡すこともできます。この場合は「別の」 属性名と属性値は複数のキーと値のペアとして扱われ、そこから抽出された「名前」と「値」が対象オブジェクトのキャッシュにコピーされます。

機能テスト コードは次のとおりです:

<script type="text/javascript" src="jqueryjs"></script>  
<script>  
obj = {};  
$data(obj, {name1: &#39;value1&#39;, name2: &#39;value2&#39;});     
documentwrite("$data(obj, &#39;name1&#39;) = " + $data(obj, &#39;name1&#39;) + &#39;<br />&#39; );  
documentwrite("$data(obj, &#39;name2&#39;) = " + $data(obj, &#39;name2&#39;) + &#39;<br />&#39;);     
for (var key in obj) 
{   
documentwrite("obj" + key + &#39;name1 = &#39; + obj[key]name1 + &#39;<br />&#39;);   
documentwrite("obj" + key + &#39;name2 = &#39; + obj[key]name2);  
}  
</script>
ログイン後にコピー

表示される結果は次のとおりです:

$.data(obj, &#39;name1&#39;) = value1  
$.data(obj, &#39;name2&#39;) = value2  
obj.jQuery1600233050178663064.name1 = value1  
obj.jQuery1600233050178663064.name2 = value2
ログイン後にコピー

上記のテスト コードでは、最初に 2 つのキーと値のペアを持つ「別の」オブジェクトを渡し、次に $ を使用します。 data(obj , 'name1') と $.data(obj, 'name2') は追加のデータを取得します。同様に、メカニズムを深く理解するために、「obj」を走査して隠れた「キャッシュ」を取り出します。 オブジェクトを取得し、「cache」オブジェクトの「name1」属性と「name2」属性の値を取得します。

jQuery.data() が実際に「obj.jQuery1600233050178663064」という名前のオブジェクトを「obj」に追加していることがわかります。 「キャッシュ」がオンになっています。 jquery.data() を使用して渡されたキーと値のペアは、「キャッシュ」にコピーされます。

次のコードを使用して同様の機能を実現できます:

$ = function() 
{  
 // Other codes      
 function setDataWithObject(cache, another) 
 {    
 for (var name in another) 
 {     
 cache[name] = another[name];    
 }   
 }     
  // Other codes      
  return 
  {    
  data : function(obj, name, value) 
  {    
   var cache = getCache(obj);        
   if (name instanceof Object) 
   {      
   setDataWithObject(cache, name)     
   } 
   else if (value === undefined) 
   {     
    return getData(cache, name);    
     } else 
     {      
     setData(cache, name, value);     
     }    
     }  
      } 
       }();
ログイン後にコピー

这段代码是在之前的代码的基础上进行修改的。首先增加了内部函数 setDataWithObject() ,这个函数的实现是遍历 “another” 的属性,并复制到 “cache” 中。

然后,在对外开放的 data 函数中,先判断传入的第二个参数的名称,如果这个参数是一个 Object 类型的实例,则调用 setDataWithObject() 方法。

为 DOM Element 附加数据

由于 DOM Element 也是一种 Object,因此之前的方式也可以为 DOM Element 赋值;但考虑到 IE6、IE7 中垃圾回收的问题(不能有效回收 DOM Element 上附加的对象引用),jQuery采用了与普通对象有所不同的方式附加数据。

测试代码如下:

<div id="div_test" />     
<script type="text/javascript" src="datajs"></script>  
<script>  
windowonload = function() 
{   
div = documentgetElementById(&#39;div_test&#39;);   
$data(div, &#39;name&#39;, &#39;value&#39;);   
documentwrite($data(div, &#39;name&#39;));  
}  
</script>
ログイン後にコピー

显示结果如下:

value
ログイン後にコピー

测试代码中,首先通过 document.getElementById 方法获取了一个 DOM Element (当然,也可以用 jQuery 的选择器),然后在这个 DOM Element 上附加了一个属性,随后就从 DOM Element 上取出了附加的属性并输出。

因为考虑到 IE6、IE7 对 DOM Element 上的对象引用的垃圾回收存在问题,我们不会直接在 DOM Element 上附加对象;而是使用全局cache,并在 DOM Element 上附加一个 uid。

实现方式如下:

$ = function() 
{   
var expando = "jQuery" + ("6" + Mathrandom())replace(/\D/g, &#39;&#39;);   
var globalCache = {};   
var uuid = 0;      
// Other codes      
function getCache(obj) 
{   
 if (objnodeType) 
 {     
 var id = obj[expando] = obj[expando] || ++uuid;     
 globalCache[id] = globalCache[id] || {};     
 return globalCache[id];    
 } else 
 {     
 obj[expando] = obj[expando] || {};     
 return obj[expando];    
 }   
 }     
  // Other codes  
  }();
ログイン後にコピー

 这段代码与之前的代码相比,增加了 globalCache 和 uuid,并修改了 getCache() 方法。

globalCache 对象用于存放附加到 DOM Element 上的 “cache”,可以视为 “cache” 的“容器”。uuid 表示 “cache” 对应的唯一标识,是唯一且自增长的。uuid 或被存放在 DOM Element 的 “expando” 属性中。 

getCache() 函数中增加了一个判断,即 “obj” 具有 “nodeType” 属性,就认为这是一个 DOM Element;这种情况下,就先取出附加在 “obj” 上的 id ,即 obj[expando] ;如果 obj[expando] 未定义,则先用 ++uuid 对其进行初始化;取出 id 之后,就到 globalCache 中找到对应的 “cache” ,即 globalCache[id], 并返回。

    到此为止,jQuery.data() 函数的实现就介绍完了;但是,这里还有一个需要思考的问题:为什不都统一用 “globalCache” 存储,而要将 “cache” 直接附加到普通对象上?我认为这应该是一种性能优化的方式,毕竟少一个引用的层次,存取速度应该会略快一些。 jQuery 中这刻意优化的地方非常多,在许多原本可以统一处理的对方都进行了特殊处理。但这在一定程度上,也造成了阅读源码的障碍。当然这是作者(及其他代码贡献者)本身的编程哲学,这里就不加评论了。


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート