学习源码第三天(短暂的坚持)
/* 给JQuery原型添加属性和方法 */ jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: core_version, //版本 constructor: jQuery, //添上constructor 指向构造函数,修复constructor init: function(selector, context, rootjQuery) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; } // Handle HTML strings if (typeof selector === 'string') { if ( selector.charAt(0) === '<' && selector.charAt(selector.length - 1) === '>' && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec(selector); }
由这段代码可知,jQuery.fn就是jQuery.prototype,现在要把jQuery的原型重写,重写一定会破坏constructor指向jQuery的这个构造函数,所以要手动添加;小写的jquery是版本号
var jq = new Jquery() console.log(jq.jquery) // 2.0.3
接下来是重点的init,没错就是那个不像构造函数的init
init: function(selector, context, rootjQuery) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; }
selector参数是选择器字符串,其他两个参数暂且不论,然后定义了match,elem;紧接着来了一个if语句,if(!selector)的意思就是selector为“”,null,undefined,false对应的情况注释给我们了HANDLE: $(""), $(null), $(undefined), $(false) 处理四种获取不到的情况,jQuery里面直接去return this;不但终止了下列代码的执行,还返回了this,这个this就是jQuery.prototype
// Handle HTML strings if (typeof selector === 'string') { if ( selector.charAt(0) === '<' && /* chatAt(下标)截取对应下标字符的意思 selector.charAt(selector.length - 1) === '>' && * 这3句判断了selector字符串是不是长<a>或<aaa>的总之要有一个尖括号,而且尖括号里面必须有字符 selector.length >= 3 */ 这句话并不能保证像<1>这种的 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else {
//除了<a>、<1>这种的,例如<aa>、<aa>11,返回的要么selector不满足rquickExpr正则匹配规则的null,要么返回一个数组
//如果是<aa>11这种返回的match = [ <aa>11,<aa>,undefined ],意思是把<aa>11这种的解析为<aa>,容错性增加 match = rquickExpr.exec(selector); }
//正则.exec()返回一个数组或null,如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式(正则1|正则2)相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式(正则1|正则2)相匹配的文本(如果有的话)
这一段是如果$()括号里面不是上述四种的情况,那么就是一个有值的字符串。再进入一个if...else if语句(这里截取的是if里面嵌套的if else语句),如果selector是一个字符串类型,那么就可以再判断他是不是一个标签类似于'<a>',三个字符尖括号开头和结尾,如果类似这种就把[null,selector,unll]这样一个数组赋值给前面定义的match,否则,match就会等于rquickExpr.exec(selector);
那么这是什么意思呢?正则的exec()方法返回的是一个数组,那么这个数组长什么样呢?上面已经定了rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,这就涉及到正则,简单的说下:
/^$/是精确匹配的意思 ?: 不储存(非贪婪匹配),以后\1引用不了,如果后面不引用,这样做可以减少内存 \s是空白符 *出现0或多次 \s*空白符出现0或多次 (<[\w\W]+>)---()表示储存起来以后可以引用,有可能不在本正则表达式引用\w 是字母,数字,下划线,小提醒一下:字母不单单是英文字母,俄文字母也行哦\W是除去\w的情况,+是出现一次以上 [^>]* 不是'>'的0次或多次 类似于<aa>这种 或<aa>11这种 |#([\w-]*) 或者'#'后匹配任意数字字符下划线- 出现0次或以上 #的情况或#aaa这种
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/ 匹配了'<aa>'、'<a>11'、'#'、'#111'这种字符串。match = [null, selector, null]是反映'<1>'、'<a>'尖括号内一个字符的情况;而match = rquickExpr.exec(selector);①反映'<aa>'、'<aa>11'、'#122'、'#'这种情况等等(也就是在rquickExpr匹配的范围内 - 尖括号内一个字符的情况 ),②甚至包括了requickExpr匹配范围之外的情况'11<aa>'、'abc'、'123'这种不符合requickExpr匹配规则的,这时候通过exec方法,如果符合匹配规则(①的情况),返回一个数组,数组的三个元素第一个是匹配的文本,第二个是与第一个子表达式匹配的文本,第三个是与第二个表达式匹配的文本;如果不符合(②的情况),match通过exec方法返回null。
顺带一提:\s*的作用是像$(' <div>')一样可以有多个空格。容错性真的好!
你的努力有资格到拼天赋的程度吗?