jQuery构造对象函数有:
- jQuery([selector,[context]])
- jQuery(element)
- jQuery(elementArray)
- jQuery(object)
- jQuery(jQuery object)
- jQuery(html,[ownerDocument])
- jQuery(html,[attributes])
- jQuery()
- jQuery(callback)
function(window,undefined){
var jQuery=(function(){
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
//这里用new,省去了构造函数jQuery()前面的运算符new,因此我们可以直接写jQuery()
},
//一堆局部变量声明
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
};
//覆盖构造函数jQuery的原型对象
jQuery.fn = jQuery.prototype ={
.....//一堆原型属性和原型方法
};
jQuery.extend = jQuery.fn.extend = function(){
....//
};
//jQuery.extend()和jQuery.fn.extend(),用于合并两个或多个对象的属性到第一个对象
jQuery.extend({
//一堆静态属性和方法
});
return jQuery;
})();
//其他模块代码
window.jQuery=window.$=jQuery;
})(window);
为什么要覆盖jQuery()的原型对象jQuery.prototype
因为在原型对象jQuery.prototype上定义的属性和方法会被所有jQuery对象继承,可以有效的减少每个jQuery对象所需的内存。
为什么要在构造函数jQuery()内部用运算符new创建并返回另一个构造函数实例
用new的原因是因为,我们每次创建一个对象或者实例的时候,都是在运算符后面跟一个new运算符
例如:
var mydate=new Date()
如果构造函数有返回值,运算符new创建的对象会被丢弃,返回值将作为new表达式的值。
jQuery通过在构造函数jQuery()内部用运算符new创建并返回另一个构造函数实例,省去了构造函数jQuery()前面的new,因此我们在创建jQuery对象时可以省略运算符new 直接写jQuery()
后面的
window.jQuery=window.$=jQuery;
也是为了更简写,因此我们在创建jQuery对象时可以写$()=jQuery()=window.jQuery
jQuery.fn.init()
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
//参数selector可以转换为false,如果是"" ,null,undefined,false ,返回this(空的jQuery,length=0)
if ( !selector ) {
return this;
}
....
}
一个普通的jQuery对象 $(“body”)
可以看到jQuery.fn.init[1]
length=1
一个空的jQuery对象
并且它什么都没有,没有context ,selector,只有原型prototype可以查看原型,它的length=0
处理nodeType,文本中有3个p
因此是jQuery.fn.init[3]
//如果参数selector是字符串
if ( typeof selector === "string" ) {
if ( selector[ 0 ] === "<" &&
selector[ 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 );
}
// 处理 $(#id)
{
elem = document.getElementById( match[ 2 ] );
//检查parentNode,因为Blackberry会返回已经不在文档中的Dom节点
if ( elem && elem.parentNode ) {
//从这里就能看到为id元素构造了length 以及手动设置第一个元素this[0]=elem
this.length = 1;
this[ 0 ] = elem;
}
//并返回了jQuery对象
this.context = document;
this.selector = selector;
return this;
}
// Easily-parseable/retrievable ID or TAG or CLASS selectors
//2.2.4版本
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
//严格控制了HTML必须以<开头,不识别"ab<div>"
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/
//1.7.3版本 #是为了防止XSS攻击
quickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
说明一下正则表达式
1、2.2.4版本不匹配”ab < d i v >”这样的字符串了,对于“#”也就直接到#id中去识别了,因此省略了 [^#<]
(不匹配#和<的字符串,如“abc”)
2、另外说一下(?:pattern),第一次遇到这种表达式(因为平时很少接触正则),这句话的作用是:匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, ‘industr(?:y|ies) 就是一个比 ‘industry|industries’ 更简略的表达式。
正则语句 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/
的测试:
所谓XSS攻击:
只参照《jQuery技术内幕》中的介绍,在应用代码中出现$(location.hash),会根据location.hash的值来执行不同的逻辑。用户可以自行在浏览器地址中修改hash值为”#”,并重新打开这个页面,如果没有#(在jQuery1.6.3之前的版本),”#”会被认为是HTML代码并创建img元素,因为src不存在,oneror事件被触发,从而弹出窗口1。这样攻击者就可以在句柄onerror事件编写恶意代码,例如,读取用户cookie,发起Ajax请求。
本文是在阅读《jQuery技术内幕》后写的,以及慕课网上的jQuery源码解析,也结合了网上的其他对jQuery的分析。
另外我阅读的jQuery源码的version 是 v2.2.4
阅读好的源码有利于对好的代码风格进行学习,由于水平有限,这些都是我的学习心得体会。