jQuery.data()는 일반 객체나 DOM 요소에 데이터를 연결(및 획득)하는 데 사용됩니다.
다음은 구현을 세 부분으로 분석합니다.
1.
이름과 값을 사용하여 개체에 데이터를 추가합니다. 즉, 세 개의 매개변수를 전달합니다. 첫 번째 매개변수는 데이터를 추가해야 하는 개체이고, 두 번째 매개변수는 데이터 이름이고, 세 번째 매개변수는 값입니다. 데이터의. 물론 값만 얻으면 세 번째 매개변수를 전달할 필요가 없습니다.
2.
다른 개체를 사용하여 개체에 데이터를 추가합니다. 즉, 두 개의 매개변수를 전달합니다. 첫 번째 매개변수는 추가해야 하는 데이터 개체("obj"라고 함)이고 두 번째 매개변수도 개체입니다("obj"라고 함). "another"입니다. "); "another"에 포함된 키-값 쌍은 다음 위치에 복사됩니다.
데이터 캐시의 "obj"("캐시"라고 부르겠습니다).
3. DOM 요소에 데이터 연결 DOM 요소도 일종의 객체이지만 IE6 및 IE7은 DOM 요소에 직접 연결됩니다. 객체의 가비지 수집에 문제가 있습니다. 따라서 우리는 이 데이터를 글로벌 캐시("globalCache"라고 함)에 저장합니다. 즉, "globalCache"에는 여러 DOM이 포함되어 있습니다. Element의 "cache"를 선택하고 DOM Element에 속성을 추가하여 "cache"에 해당하는 uid를 저장합니다.
이름과 값을 사용하여 객체에 데이터 추가
jQuery.data()를 사용하여 일반 객체에 데이터를 추가할 때 핵심은 객체에 "캐시"를 연결하고 특수 속성 이름을 사용하십시오.
데이터를 저장하는 "캐시"도 객체입니다. "obj"에 첨부하는 데이터는 실제로 "캐시"의 속성이 됩니다. 그리고 "캐시"는 "obj"의 속성입니다. jQuery 1.6에서 이 속성의 이름은 "jQuery16"에 임의의 숫자를 더한 것입니다(아래 언급됨). "jQuery16018518865841457738").
다음 코드를 사용하여 jQuery.data()의 기능을 테스트할 수 있습니다.
<script type="text/javascript" src="jqueryjs"></script> <script> obj = {}; $data(obj, 'name', 'value'); documentwrite("$data(obj, 'name') = " + $data(obj, 'name') + '<br />'); for (var key in obj) { documentwrite("obj" + key + 'name = ' + obj[key]name); } </script>
표시된 결과는 다음과 같습니다.
$.data(obj, 'name') = 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, ''); 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" 속성을 설정하는 데 사용되는 setData() 함수가 있는데, 실제로는 캐시[이름]의 값을 설정하는 것입니다.
뒤에는 "obj"에서 "캐시"를 가져오기 위한 getCache()가 옵니다. 즉, obj[expando] if obj[expando];
비어 있으면 초기화가 수행됩니다.
마지막으로 데이터 메소드가 노출됩니다. 먼저 들어오는 "obj"에 따라 두 개의 매개변수가 전달되면 "obj"에 첨부된 "캐시"를 얻습니다. getData() 메서드; 세 개의 매개변수가 전달되면 setData() 메서드가 호출됩니다.
다른 객체를 사용하여 객체에 데이터 추가
이름과 값을 제공하여 값을 할당하는 것 외에도 다른 객체("another")를 매개변수로 직접 전달할 수도 있습니다. . 이 경우에는 "다른" 속성 이름과 속성 값은 여러 키-값 쌍으로 처리되며, 여기서 추출된 "이름"과 "값"은 대상 개체의 캐시에 복사됩니다.
기능 테스트 코드는 다음과 같습니다.
<script type="text/javascript" src="jqueryjs"></script> <script> obj = {}; $data(obj, {name1: 'value1', name2: 'value2'}); documentwrite("$data(obj, 'name1') = " + $data(obj, 'name1') + '<br />' ); documentwrite("$data(obj, 'name2') = " + $data(obj, 'name2') + '<br />'); for (var key in obj) { documentwrite("obj" + key + 'name1 = ' + obj[key]name1 + '<br />'); documentwrite("obj" + key + 'name2 = ' + obj[key]name2); } </script>
표시 결과는 다음과 같습니다.
$.data(obj, 'name1') = value1 $.data(obj, 'name2') = value2 obj.jQuery1600233050178663064.name1 = value1 obj.jQuery1600233050178663064.name2 = value2
위 테스트 코드에서는 먼저 키를 넣습니다. -두 개의 값 쌍 "또 다른" 개체가 전달된 다음 $.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('div_test'); $data(div, 'name', 'value'); documentwrite($data(div, 'name')); } </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, ''); 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
中这刻意优化的地方非常多,在许多原本可以统一处理的对方都进行了特殊处理。但这在一定程度上,也造成了阅读源码的障碍。当然这是作者(及其他代码贡献者)本身的编程哲学,这里就不加评论了。