JQuery源码简单分析
JQuery源码分析
我们通过对jQuery1.4.2版本的分析,了解jQuery原理
最外层
(function(window,undefined){
})(window)
- 将代码放到匿名函数中,用闭包的特性,防止过多的变量污染到全局
- 将window传递到自身的AO上,不用跳到全局寻找,速度更快
- 函数形参使用undefined,避免ie6/7情况下关键字undefined可复制的现象,保证函数的运行
选择器
初始化代码
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
//调用fn属性的init方法
}
//定义$和Jquery 使用noConflict方法让出$的控制权
//定义正则表达式用于解析selector
//定义方法,基于Object和Array的原型
//init方法
//将$和Jquery暴露在全局中
Jquery作为一个方法,传入选择器和文本
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
if ( typeof selector === "string" ) {
//通过定义好的正则和方法对传入的selector进行判断,确定传入值是html或者id,如果传入的为html,则创建dom对象,如果为类或者伪类选择器,或者为表达式,则选择对象,返回包装后的dom元素
}
//定义Jq方法,属性
}
}
jQuery.fn.init.prototype = jQuery.fn;
jQuery只是一个普通函数,未定义prototype的情况下,原生的prototype应为Object;
定义jQuery中的fn属性,并且将jQuery的prototype指向该对象,为了确保Jquery在实例化的同时直接通过原型使用其中的方法.
但是我们在全局中使用$()时,只是对jQuery.fn.init进行了实例化,并未对jQuery进行实例化,所以,我们设置jQuery.fn.init.prototype = jQuery.fn
,其实就是定义jQuery.fn.init.prototype = jQuery.prototype
,表达的意思就是jQuery.fn.init的实例化对象就等价于jQuery的实例化对象,他们公用的方法和属性都存在于jQuery.fn中.
It gives the init() function the same prototype as the jQuery object. So when you call init() as a constructor in the "return new jQuery.fn.init( selector, context );" statement, it uses that prototype for the object it constructs. This lets init() substitute for the jQuery constructor itself
保障我们在使用Jquary.fn.init实例化的对象时,可以直接调用JQuery.fn中的属性.
独立选择器
Jquery的选择器被称之为sizzle选择器,我们仿照源码写一个选择器
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
jQuery.fn = {
init:function(selector){
var rs = null;
this.length = null;
if(selector.substr(0,1) == '#') { // ID选择器
rs = document.getElementById(selector.slice(1));
} else if(selector.substr(0,1) == '.') { // 类选择器
rs = document.getElementsByClassName(selector.slice(1));
} else { // 标签选择器
rs = document.getElementsByTagName(selector);
}
if(rs !== null && rs.length ===undefined) {
this[0] = rs;
this.length = 1;
} else if(rs !== null && rs.length !==undefined){
for(var i=0; i<rs.length; i++) {
this[i] = rs[i];
}
this.length = rs.length;
}
return this;
}
}
})(window)
CSS方法
我们如果去除刚刚所写的jQuery.fn = jQuery.prototype
和jQuery.fn = jQuery.fn.init.prototype
,在/代码块上直接添加css方法,方法不能正常使用
(function(window,undefined){
window.$ = window.JQuery;
var jQuery = function(selector){
return new JQuery.fn.init(selector)
}
jQuery.fn = {
css:function(){
alert(3)
}
init:function(selector){
//...
}
}
})(window)
这是因为我们返回值是JQuery.fn.init的实例化对象,该对象只能访问自身或者原型上的属性和方法,所以我们只需要将JQuery.fn.init的原型指向jQuery.fn,即可在全局访问css方法
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
jQuery.fn = {
css : function(attr , value) {
for(var i=0; i<this.length; i++) {
this[i].style[attr] = value;
}
},
init:function(selector){
//...
}
}
jQuery.fn.init.prototype = jQuery.fn;
})(window)
方法的扩展
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
JQuery.fn = {
css:function(attr , value) {
for(var i=0; i<this.length; i++) {
this[i].style[attr] = value;
}
},
attr:function(attr , value) {
for(var i=0; i<this.length; i++) {
this[i][attr] = value;
}
},
init:function(selector){
//...
}
}
JQuery.fn.init.prototype = JQuery.fn;
})(window)
我们的库完成并发布后,用户如何扩展?
我们需要给用户提供一个接口,用于扩展库的功能 -> 使用复制继承
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
JQuery.fn = {
extend:function(obj) {
for(var k in obj) {
this[k] = obj[k];
}
},
init:function(selector){
//...
}
}
JQuery.fn.init.prototype = JQuery.fn;
})(window)
此后,我们就可以在jQuery外部书写方法,复制继承给fn对象,通过init初始化访问而不改变原内核.
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
JQuery.fn = {
extend:function(obj) {
for(var k in obj) {
this[k] = obj[k];
}
},
init:function(selector){
//...
}
}
JQuery.fn.init.prototype = JQuery.fn;
JQuery.fn.extend({
html : function(val) {
for(var i=0; i<this.length; i++) {
this[i].innerHTML = val;
}
}
});
})(window)
同理,函数也可以看作为对象,所以我们可以将属性挂载在JQuery本身上
(function(window,undefined){
window.$ = window.JQuery;
var JQuery = function(selector){
return new JQuery.fn.init(selector)
}
JQuery.fn = {
init:function(selector){
//...
}
}
JQuery.fn.init.prototype = JQuery.fn;
JQuery.extend = JQuery.fn.extend = function(obj){
for(var k in obj) {
this[k] = obj[k];
}
};
JQuery.fn.extend({
html : function(val) {
for(var i=0; i<this.length; i++) {
this[i].innerHTML = val;
}
}
});
JQuery.extend({
get:function(url,succ)
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(this.readyState == 4){
succ(this.responseText)
}
}
xhr.open('get',url,true);
xhr.send(null)
})
})(window)
从事实上来说
jQuery.extend(object) 为扩展jQuery类本身.为类添加新的方法。
jQuery.fn.extend(object) 给jQuery对象添加方法。