jquery.jsを読み解くを見て勉強(第2回分)

id:lesamoureuses:20080805:1217957807に引き続き第2回分

jQuery.fn.attr

attr()は

  1. attr(name)というgetterと、
  2. attr(name, value)というsetterと、
  3. attr({name1: value1})というsetter

がある。
追記

  1. attr(name, fn)というsetterと、
  2. attr({name1: fn1})というsetter

もあった。(eachで対象要素全てのnameという属性にfnの戻り値をsetする)


第3引数のtypeはユーザが使うことはなく、この後に出てくるjQuery.fn.cssから呼び出されるときに使われる。


また、実際に値を戻すのはjQuery.attrで、そこに渡すためのインタフェースみたいなもの。

attr(name)の場合

attr(name)の場合はその属性の値か、undefinedを返す
ここで&&と||の復習。
どっちも最後に評価したものの値が返るのは同じ。
まず、&&の場合

真 && 真       // 後の真が返る
真 && 偽       // 偽が返る
偽 && 何でも   // 偽が返る

前から評価していき、真が続く限りその次を評価する。
偽だったらそこで終わるので偽の値が返る。

1 && 2       // 2
1 && 0       // 0
false && 3   // false

次、||の場合

真 || 真       // 前の真が返る
偽 || 偽       // 後の偽が返る
偽 || 真       // 真が返る

前から評価していき、偽が続く限りその次を評価する。
真だったらそこで終わるので真の値が返る。

1 || 2       // 1
false || 0   // 0
false || 3   // 3


で、178行目は

return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;

となってる。
this.lengthって必ず1な気がするのだけど、0のときってあるのかな?
1だとすると、jQuery[ type || "attr" ]( this[0], name )か、それが定義されてなければundefinedを返す
typeはこの次のjQuery.fn.cssを例に出すとcurCSSで、this[0]は要素なので、
要素と属性名をjQuery.curCSSまたはjQuery.attrに渡してる

attr(name, value)、attr(name, fn)の場合

options={name, value}というオブジェクトを用意して、次のattr({name1: var1})に渡す

attr({name1: value1})、attr({name1: fn1})の場合

jQuery.fn.eachを使って、対象となるjQueryオブジェクトすべてに対して関数を実行
その関数の中では{name1: value1, name2: value2}のようなパラメータを分解してjQuery.attrでひとつずつsetしていく
たとえば、

$('h2').attr({'title': 'h5', 'class': 'h'})

こういうのがあると、ページ上の<h2>がすべて<h2 title="h5" class="h">になる。
attr({name1: fn1, name2: fn2, ...})の場合はfnを一つずつ実行し、returnの値をnameにsetしていく。
fnの引数は要素のindexが入ってる。
例は以下。

$('h2').attr({
    'id': function (i) {
        return "h2-id" + i;
    },
    'class': function(i) {
        return 'h2-class' + i;
    }
})

ページ上の<h2>が、
<h2 id="h2-id0" class="h2-class0">
<h2 id="h2-id1" class="h2-class1">
...
のようになる。

jQuery.fn.text

パラメータがある(ただし、パラメータがオブジェクトではない)場合は、テキストノードを設定する
# パラメータとしてjQueryオブジェクトを渡すとその中のtextを取得する仕様のため

ownerDocumentはノードが含まれるトップレベルのドキュメントオブジェクトを返すけど、
自分自身がdocumentの場合はnullになるので「|| document」ってしてるのかな。

パラメータでjQueryオブジェクトが渡された場合はその中のtextを取ってくる
たとえば、

$('h2').text($('h1'))

の場合は<h2>のtextではなく、<h1>のtextを取得する

jQuery.fn.wrapAll

initメソッドでやったとおり、

jQuery( html, this[0].ownerDocument )

$(this[0].ownerDocument).find(html)

と同義。
そのcloneを作って、wrapしたい要素の1番目の前にinsertする。
mapの中でやってることは、

<p>a</p>
<p>b</p>

の時、

$('p').wrapAll('<div><span>')

を実行すると、

<div>
  <span>
    <p>a</p>
    <p>b</p>
  </span>
</div>

と一番子供の要素でwrapするようにelem.firstChildで下がっていってる。
この場合はspan。

jQuery.fn.find

/[^+>] [^+>]/.test( selector )

は、先祖関係でマッチしたときに結果がダブるのでuniqueにしてる。
たとえば、

<div>
  <a href="">link</a>
  <div>
    <a href="">link</a>
  </div>
</div>

のとき、

jQuery.find('div a', $('body').get(0))  // $('body').get(0) はbody要素

とすると、2番目の<a>が2回ヒットする。なので、ユニークにしてると。
ただ、

selector.indexOf("..") > -1

がわからないな。「..」で始まるselectorってなんだろう?

jQuery.fn.clone

イベントのコピー部分。
325行目「if ( events === true )」は厳密等価演算子
「==」だと「1 == true」が真になってしまうので、引数がちゃんと「true」になってるかチェックしてると。

find('*').andSelf()でコピーしたノード全てに対しeachで処理。
nodeTypeがテキストノード(3)の時は抜ける。
他のときは、jQuery.dataで'events'を取り出してコピーしたオブジェクトに割り当て直してるのだけど、
'events'はjQueryがセットしてるものだから、jQuery(...).bind()でセットしたイベントでないとコピーされない。

<html> 
<head> 
<script type="text/javascript" src="http://code.jquery.com/jquery-1.2.3.min.js"></script> 
<script type="text/javascript">
$(function(){
	$('div:first').get(0).addEventListener('click', click, false);
});
function click(e){
	var elem = e.currentTarget;
	$(elem).dblclick(function(){
		console.debug('dblclick')
	});
	var events = $.data(elem, 'events');
	console.debug(events); // dblclick の方しか出てこない
	$(elem).clone(true).appendTo('body'); // dblclick の方だけコピーされる
}
</script>
</head> 
<body> 
	<div>okとでる</div> 
</body> 
</html> 

jQuery.fn.not

isSimple.test( selector )でselectorのチェック。
isSimpleは

var isSimple = /^.[^:#\[\.]*$/;

だからselector一つならマッチするけど、
'.class, #id'みたいにいくつかのselectorをいっぺんに受け取った場合はfalseになる
その場合は

0356:        selector = jQuery.multiFilter( selector, this );

でmultiFilterに渡してselectorを','区切りの配列にしてる

jQuery.fn.val

432行目。
radioボタンやcheckboxの時に配列を渡すことで一括で複数チェックすることができる。

0433:        this.checked = (jQuery.inArray(this.value, value) >= 0 ||
0434:          jQuery.inArray(this.name, value) >= 0);

と書いてあるとおり、valueかnameに指定しておく必要がある。
例えば

<input id="1" value="one" name="checkboxname" type="checkbox"><label for="1">1</label>
<input id="2" value="two" name="checkboxname" type="checkbox"><label for="2">2</label>
<input id="3" value="three" name="checkboxname" type="checkbox"><label for="3">3</label>

なら

$(':checkbox').val(['one', 'three'])

とした時に1番目と3番目がチェックされる。