jQuery 1.6.2 源码分析(链式调用)
2018-09-10 本文已影响5人
千羽之城88
看了 jQuery
源码很久,一直不是很理解为什么 jQuery
可以链式操作,现在来分析一下源码,难免有错漏之处。先看看链式调用的例子:
var obj = { // every method returns obj---------v
first: function() { alert('first'); return obj; },
second: function() { alert('second'); return obj; },
third: function() { alert('third'); return obj; }
}
obj.first().second().third();
var obj = { // every method returns obj---------v
first: function() { alert('first'); return this; },
second: function() { alert('second'); return this; },
third: function() { alert('third'); return this; }
}
obj.first().second().third();
从例子我们可知,即每个节点在其内部返回的值为外部的obj
或者this
关键字,即实现了链式调用。现在我们改变一下函数的返回值给obj
:
var obj = (function(){
this.first = function(){alert('first'); return this};
this.second = function(){alert('second'); return this};
return this; // 将内部函数暴露给外部对象
})();
obj.first().second();
我们来总体上看jQuery
是如何创建的。
(function(window, undefined){
var document = window.document,
navigator = window.navigator,
location = window.location;
...
var jQuery = (function(){
var jQuery = function(selector, context){
return new jQuery.fn.init(selector, context, rootjQuery);
}
...
jQuery.fn = jQuery.prototype = {
constructor:jQuery,
init: function(selector, context, rootjQuery){
- selector
}
};
...
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function(){...};
jQuery.extend(...); // extend 静态方法
...
rootjQuery = jQuery(document);
return jQuery; // 返回并覆盖外部变量jQuery
})();
...
window.jQuery = window.$ = jQuery
})(window)
现在开始看源码。jQuery
库的最外层是一个 匿名函数,里层第一层先定义了 jQuery
这个变量,然后执行一个匿名函数(内部定义了很多方法和节点),函数返回值为 jQuery
,这样就是我们上面说的 链式调用。
(function(){ // 匿名函数,立即运行
var jQuery = (function(){ // 匿名函数
....
return jQuery; //所有属性返回给外部jQuery变量
})();
window.jQuery = window.$ = jQuery // jQuery 变量赋值给$
})()
现在我们进入jQuery
内部,我们发现内部也定义了一个同名的jQuery
变量,这个内部变量是通过它自己的init
方法实例化的。
//(function(){ // 匿名函数,立即运行
//var jQuery = (function(){ // 匿名函数
var jQuery = function(selector, content){
return new jQuery.fn.init(selector, content, rootjQuery); // 实例化jQuery的init方法
};
//return jQuery; //所有属性返回给外部jQuery变量
//})();
//window.jQuery = window.$ = jQuery // jQuery 变量赋值给$
//})()
现在我们进入内部的jQuery
看看:
//(function(){ // 匿名函数,立即运行
//var jQuery = (function(){ // 匿名函数
//var jQuery = function(selector, content){
//return new jQuery.fn.init(selector, content, rootjQuery); // 实例化jQuery的init方法
//};
jQuery.fn = jQuery.prototype = { //以下是jQuery原型的扩展
constructor: jQuery, // jQuery.fn.constructor = jQuery,激活init方法后,所有的contructor指向jQuery,以便继承
init: function(selector, context, rootjQuery){
...
// 这里的return this是返回各个类型的selector
- $(null): return this; // 直接返回
- $(DOMElement): return this; // DOM元素
- $(body): return this; // body
- $(html)->$(array): return merge(this, selector); // 如果是html标签则转为数组
- $(#id): return this; // #id
- $(function): ...
...
return jQuery.makeArray(selector, this); //其他情况
}
....
jQuery.fn.init.prototype = jQuery.fn; // ini方法指向fn的原型
}
//return jQuery; //所有属性返回给外部jQuery变量
//})();
//window.jQuery = window.$ = jQuery // jQuery 变量赋值给$
//})()
内部的jQuery
扩展很多方法,为了防止原型污染,将接下来定义的所有方法赋值给fn
,并将constructor
指向自己。
现在我们简化一下jQuery
的代码实现一个精简版本:
var jquery = (function(){ // 外部的jQuery
var document = window.document;
var jquery = function(selector, context){ // 内部同名的jQuery
return new jquery.fn.init(selector, context);
};
jquery.fn = jquery.prototype = { // 拷贝jQury原型链,防止原型污染
constructor: jquery, // 新原型链constructor依然指向内部的jQuery
init: function(selector, context){
var elem = document.getElementById(selector); // 只接受ID的情况
this.context = document; // 指定selector所在环境
this.selector = selector; // 返回ID本身
return this;
},
selector:"",
};
return jquery;
})();
window.jquery = window._$ = jquery;
_$('#question-header') // 返回正确
返回的结果