在 叶小钗 的博客中看到一段关于遍历的代码
var ajQuery = {}; function dir(elem, dir, until) { var matched = [], truncate = until !== undefined; while ((elem = elem[dir]) && elem.nodeType !== 9) { if (elem.nodeType === 1) { if (truncate) { if (elem.nodeName.toLowerCase() == until || elem.className == until) { break; } } matched.push(elem); } } return matched; } // 迭代器 jQuery.each({ parent: function(elem) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function(elem) { return dir(elem, "parentNode"); }, parentsUntil: function(elem, until) { return dir(elem, "parentNode", until); } }, function(name, fn) { ajQuery[name] = function(until, selector) { return fn(until, selector); }; }); $("#test1").click(function() { var item = $('.item-1'); alert(item.parent()[0]) alert(item.parents().length) alert(item.parentsUntil('body').length) }) $("#test2").click(function() { var item = document.querySelectorAll('.item-1')[0] alert(ajQuery.parent(item)) alert(ajQuery.parents(item).length) alert(ajQuery.parentsUntil(item, 'body').length) })
jQuery 中的each 不仅仅是用来遍历jQuery对象,还可以用来作为合并接口。
jQuery.each({ parent: function(elem) {}, parents: function(elem) {}, nextAll: function(elem) {}, prevAll: function(elem) {}, ................ }, function(name, fn) { api[name] = function(until, selector){ }; });
其中就利用了$.each(fn)的特性,jQuery 源码中 :
each: function( obj, callback, args ){}
为obj 执行回调函数 callback。
里面的巧妙之处在于:
在为obj执行回调函数的时候,回调函数为新的对象 ajQuery{},绑定了新的属性(或方法)
function(name, fn) {
ajQuery[name] = function(until, selector) {
return fn(until, selector);
};
}
测试:
jQuery.each({ say: function(cont){ console.log(cont); } }, function(name, fn) { ajQuery[name] = function(until, selector) { // 传递fn参数 return fn(until, selector); }; });
$("#test1").click(function() {
ajQuery.say('oooooooo'); // oooooooo
})
所以根据这个推论,总结each的原理:
1. 遍历obj对象;
2. 为callback传参;
3. 为每个obj[i],绑定callback
模拟写了个版本:
o = {}; test = { fn1: function(){}, fn2: function(){}, getDom: function(dom, fn){ var t = document.getElementById(dom) return t.onclick = function(){ fn() } }, each: function(c, fn){ for(k in c){ fn.call(c[k],k,c[k]); } return c; } } test.each({ say: function(cont){ console.log(cont) }, walk: function(length){ console.log('walk '+length); } }, function(name, fn) { o[name] = function(name){ return fn(name); } })
// 调用
test.getDom('btn', function(){
o.say('aaaaa');
})