写在前面
前面陆陆续续写了jQuery源码的一些分析,尽可能地想要cover里面的源码细节,结果导致进度有些缓慢。jQuery的源码本来就比较晦涩,里面还有很多为了解决兼容问题很引入的神代码,如果不google的话压根不知道那一段段代码为什么会存在于人世。
于是就一直在重复坐着这么件事情,到处谷歌或者请教别人,这段兼容代码是为解决神马问题引入的。好不容易把所有的源码细节搞清楚,喝着咖啡对着电脑欣赏自己的劳动成果,内心却闪过一丝奇怪的感觉:我花了这么长的时间究竟做了什么?就为了搞清楚这段常理无法解释的代码?而在这之前已经有无数仁人志士在这上面浪费了自己多少宝贵的时间。
当然,学习jQuery源码对于我这种老菜鸟还是很有助益的,只不过需要换种方式,不再去抠一些无谓的细节了,有些比较难理解的东西就直接扔出来看下园里的朋友们帮忙解答下了。社会化写作似乎是更好的方式,之前也想过把系列文章扔github让别人来帮忙完善,不过显然对于大部分人来说这种方式成本还是太高,而自己写的东西暂时也没有说让人家去fork然后pull request的价值,就作罢了。
技术无关的内容就此打住,还是老老实实开始我的源码分析。里面标疑惑的地方,是还没来得及去抠的细节(一般就是一些正则神马的),围观的群众如果能够帮忙解答下那是真真的好~~
简单例子
jQuery.fn.html()同样属于使用频率比较高的接口,从它的接口文档http://api.jquery.com/html/,可知有如下几种用法,假设有如下HTML片段
<div id="casper"> <span>name:</span> <span>casper</span> </div>
读取:$(selector).html()
运行下面代码
console.log( $('#casper').html() );
输出:
<span>name:</span>
<span>casper</span>
设置一:$(selector).html(value)
还是上面的HTML,运行下面脚本
$('#casper').html('<p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p>');
原本的HTML变成
<div id="casper"><p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p></div>
设置二:$(selector).html(callback)
在上面例子中,HTML变成如下
<div id="casper"><p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p></div>
运行如下代码,参数 index、html 分别代码什么,见下面输出即可,不赘述
$('#casper p').html(function(index, html){
return index + '、原本的内容:'+ html;
});
结果原来的HTML变成(为方便查看进行了适当格式化)
<div id="casper"> <p>0、原本的内容:大家好,我是第一段文本</p> <p>1、原本的内容:大家好,我是第二段文本</p> </div>
源码分析
下面湿jQuery.fn.html 的源码,就直接贴上来了,一点都不意外,又见到了全知全能的jQuery.access方法。。。这里我们先不立即展开,下文慢慢分析
html: function( value ) { return jQuery.access( this, function( value ) { var elem = this[0] || {}, i = 0, l = this.length; if ( value === undefined ) { return elem.nodeType === 1 ? elem.innerHTML.replace( rinlinejQuery, "" ) : undefined; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1></$2>" ); try { for (; i < l; i++ ) { // Remove element nodes and prevent memory leaks elem = this[i] || {}; if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch(e) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }