jQuery源码二周目#1 整体架构
2020-07-21 本文已影响0人
柠檬果然酸
jQuery无new构建
首先说说$()
是个什么东西,它其实就是一个方法(因为js中可以用$
命名),它等价于jQuery()
。
所有声明的全局变量都是挂载在window
下的,也就是说可以通过window.$
达到调用jQuery的效果。
然后就说道jQuery的无new构建,怎么才能做到调用一次方法创建一个对象,答案如下:
var jQuery = function(selector, context) {
return new jQuery();
}
很可惜上面的答案是错的,这样会导致死循环,无限的自己创建自己。不过和真正的答案很接近了。正确代码如下:
var jQuery = function(selector, context) {
return new jQuery.fn.init();
}
jQuery.fn = jQuery.prototype = {
init: function() {
}
}
这样就不会出现死循环。然后jQuery的整体思路是通过$()
创建一个新的jQuery对象,jQuery的所有方法写在原型中,这样所有的对象都能够共用原型方法,节省内存开支。
jQuery.fn = jQuery.prototype = {
init: function() {
},
method1: function () {}, // 方法1
method2: function () {}, // 方法2
// 更多方法...
}
我们预想的是通过$()
创建一个jQuery对象,然后对象中有着method1()
、method2()
等等方法,但是实际上你会发现里面空空如也,因为我们创建的是jQuery.fn.init
对象而非jQuery
对象。这个问题也好解决,就是通过简单的一行jQuery.fn.init.prototype = jQuery.fn;
搞定。
原型小知识点:如果在对象没有找到目标属性,就去对象的原型中去查找。上代码有助于理解:
function fn() {
}
fn.prototype = {
name: '柠檬'
}
var fn1 = new fn();
console.log(fn1.name); // 柠檬
整体结构
(function(window, undefined) {
var jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context, rootjQuery);
}
jQuery.fn = jQuery.prototype = {
init: function(selector, context, rootjQuery) {
}
}
jQuery.fn.init.prototype = jQuery.fn;
})(window);
整个结构用一个即时函数包裹整个jQuery源码,这样能够保证jQuery内定义的属性不会对我们造成影响。即时函数传入了一个window
对象,其目的是将$
和jQuery
挂载在window
下作为全局函数。
jQuery第一步就完成了,第一步还是挺简单,到了后面诸位就会明白读懂源码是多么难的一件事,这需要耐心,为什么这么说,因为一段代码你可能前99次都看不懂。当然真实的情况不会这么夸张,以我的经验最多几十遍就懂了。