项目中有一个逻辑是这样的: 对当前元素的外层<li>元素进行操作, 我的做法是这样的:$(someElement.parents('li')).xxx
由于当前元素外层只有一个li元素,当时就没有多想,后来仔细查看parents(selector)方法的说明,发现调用这个方法之后会返回所有匹配selector的元素;
按理说,返回值应该是一个数组或者类似数组的结构猜对,而在这种结构上调用单个元素的方法(比如attr('id'))感觉上应该报错才对;
然后做了如下实验:
<!DOCTYPE html>
<html>
<head>
<style>
b, span, p, html body {
padding: .5em;
border: 1px solid;
}
b { color:blue; }
strong { color:red; }
</style>
<script type="text/javascript" src="/jquery/jquery.js"></script>
</head>
<body>
<div id="div1">
<p>
<div id='div2'>
<span>
<b>我的父元素是:</b>
</span>
</div>
</p>
</div>
<script>
var parentEls = $("b").parents('div');
var names = '';
names = $(parentEls).attr('id');
$("b").append("<strong>" + names+ "</strong>");
console.info($(parentEls));
</script>
</body>
</html>
发现在element.parents(selector)的返回值上调用attr('id')时,jquery默认是在第0个祖先上调用此方法,,即所有祖先中最接近element的那个祖先,如下图:
一开始查看parents(selector)的实现源码,没怎么看懂,今天看了一下attr(xxx)的源码,
jQuery.fn.extend({
attr: function( name, value ) {
return access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
return this.each(function() {
jQuery.removeAttr( this, name );
});
}
});
然后找到了access.js:
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
len = elems.length,
bulk = key == null;
// Sets many values
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
} else if ( value !== undefined ) {
chainable = true;
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// Bulk operations run against the entire set
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
if ( fn ) {
for ( ; i < len; i++ ) {
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
//好像原因就在这里:elems[0]
len ? fn( elems[0], key ) : emptyGet;
};
大概就是在第0个元素上调用的方法,所以我在代码中那么写就歪打正着了,如果元素外层有不止一个匹配selector的祖先,而我要在第二个祖先上调用方法,这么写就会出错了;