jQuery 是如何工作的
在本文中,我将展示一个简化的 jQuery 库源代码版本,以解释 $()/jQuery() 函数如何生成包装集,从而允许添加自定义函数。
引言
jQuery 是当今最流行的 JavaScript 库。它使用 CSS 选择器风格的语法将文档对象模型 (DOM) 中的元素获取到包装的元素集中,然后使用 jQuery 函数操作包装集中的元素以实现不同的效果。尽管使用 jQuery 的方式非常简单直观,但我们仍然应该了解其幕后发生的事情,以便更好地掌握这个 JavaScript 库。
jQuery 中的基本概念
在我们深入研究 jQuery 库之前,应该了解一些 jQuery 的基本概念。
$/jQuery 对象和 $()/jQuery() 函数
$/jQuery 对象是一个全局对象,所有 jQuery 函数都通过它访问。
它也是一个函数对象,因此最常见的用法是通过 $()/jQuery() 函数。$()/jQuery() 函数可用于选择 DOM 中的一组元素。它也称为包装函数。使用 $()/jQuery() 函数的一个简单例子是:
$(“#ABC”);
或
jQuery(“#ABC”);
传递给 $()/jQuery() 函数的参数是选择器。选择器是一种具有 CSS 选择器风格语法的表达式。在上面的例子中,我试图选择 id 等于 #ABC 的元素。
包装集
包装集是一个类数组结构,其中包含所有选定的 DOM 元素。上面的 $(“#ABC”) 返回一个包装集。您可以像数组一样遍历包装集,或通过索引访问单个元素。更重要的是,您可以将 jQuery 函数应用于所有选定的元素。
jQuery $()/jQuery() 函数的幕后工作原理
由于大多数 jQuery 函数调用都以 $()/jQuery() 函数开头,因此我们需要了解它内部发生的事情。在深入 $()/jQuery() 之前,让我们先看看 $/jQuery 对象在哪里定义。$/jQuery 对象是访问 jQuery 函数的入口点。它是在 jQuery 中定义的全局函数变量。以下是 jQuery 定义它的源代码行:
// Expose jQuery to the global object window.jQuery = window.$ = jQuery;window 对象代表浏览器中的一个打开的窗口,将 $/jQuery 放在 window 下面,它就被定义为一个全局对象,可以在当前打开的窗口中访问。
但是,上面源代码行末尾的“jQuery”是什么意思?它是在 jQuery 库的开头声明的:
var jQuery = (function() { …所有的魔力都发生在 jQuery 对象声明表达式内部,但如果直接看它,你会感到困惑,所以我会在我们继续之前简化它。
简化的 jQuery 库源代码
免责声明:简化的版本仅用于研究目的。它实际上没有 jQuery 提供的所有基本功能。切勿在实际项目中使用它。
var jQuery = (function () { // Define a local copy of “k” var k = function (selector, context) { // The k object is actually just the init constructor 'enhanced' var kobj = new k.fn.init(selector, context); return kobj; }; //Define k’s fn prototype, specially contains init method k.fn = k.prototype = { init: function (selector, context) { if (!selector) { return this; } } }; // Give the init function the “k” prototype for later instantiation k.fn.init.prototype = k.fn; // Return “k” to the global object return k; })();从上面的源代码中,您可以看到 jQuery 函数变量被定义并赋值为匿名函数调用的结果。
侧边栏:如何定义匿名函数 在 JavaScript 中,您可以定义一个匿名函数并立即调用它。 例如, (function () { alert(“hello world”); })();通过放置函数字面量 function() { alert(“hello word”); }放入括号中 (function() { alert(“hello world”); })您可以通过外部括号立即调用它。 |
在匿名函数内部,定义了一个名为 k 的函数,其签名如下:
function (selector, context)第一个参数是选择器,第二个参数是上下文。在原始 jQuery 源代码中,函数 k 实际上命名为 jQuery,这可能会与最外层的 jQuery 函数变量混淆。
在函数 k 内部,会创建一个 init 函数类的实例并返回。init 函数类稍后定义为 k 的原型方法。这是一种 JavaScript 风格的“类”。
在函数 k 声明之后,将一个匿名函数类定义为 k 的原型。Prototype 是 JavaScript 函数类上的一个特殊属性,用于指向另一个函数对象。因此,该函数类的所有实例都可以访问原型函数类中定义的成员函数。在这里,init 方法可供 k 函数类的所有实例使用。init 方法的签名如下:
function (selector, context)k 的原型有一个 init 成员方法,同时,init 函数的原型被赋值为 k 函数的原型。这是一个循环引用,通常在正常的编程实践中应避免,但这是 jQuery 使 init 函数的返回能够访问 k 上定义的所有方法的途径。
侧边栏:函数是 JavaScript 中的一等公民 JavaScript 是一种函数式编程风格的语言,但函数并非我们传统意义上的纯函数。函数可以动态创建,可以拥有属性和方法,并且可以传递给其他函数。如果您想以传统方式调用 JavaScript 函数,可以这样做: function display() { alert(“hello world”); } display();如果您想使用函数作为类,那么您可以这样做: function Car(model) { this.Model = model; this.Drive = function() { alert(“Go”) } } var car = new Car(“Ford”);因此,函数语句实际上用于定义一个 Car “类”。Car 类有一个 Model 属性,它通过函数类构造函数中的参数进行初始化,还有一个 Drive 方法。因此,您可以创建任意数量的 Car 类实例。但是,JavaScript 的类不是真正的类,因为它没有真正具有面向对象语言中类的三个关键特征。 |
k 的原型函数定义方式称为函数字面量。jQuery 中广泛使用它来达到不同的目的。
侧边栏:JavaScript 中定义函数的不同方式 1. 使用函数语句定义函数 function open() { //open logic }2. 使用函数字面量定义函数 使用字面量可以定义的最简单的函数是这样的: var o = { }同样,您可以使用字面量来定义一个函数“类” var apple = { type: “macintosh”, color: “red”, getInfo: function() { return this.color + ‘ ‘ + this.type + ‘ apple’; } }3. 使用 Function 对象定义函数 Function 对象是 JavaScript 的内置对象。在 JavaScript 中,我可以这样做: var add = new Function(a, b, “return a + b;”);来定义一个名为“add”的函数。Function 会将前两个参数“a”和“b”视为函数参数,并将最后一个参数“return a + b”视为函数体。 |
之后,内部的 k 函数被返回到外部变量 jQuery。jQuery 获得的不只是一个 k 函数,还有一个 k 函数所在的闭包。
侧边栏:JavaScript 中的闭包是什么 闭包是 JavaScript 在将内部函数返回到外部时创建的一个上下文,因此内部函数仍然可以访问那些局部变量。 闭包的一个例子是这样的: var addition = function(numberA) { return function(numberB) { alert (numberA + numberB); }}因此,您可以创建具有指定 numberA 的 addition 实例。 var add2 = addition(2); var add3 = addition(3); add2(3); // it will display 5 add3(3); // it will display 6 |
最后,k 函数被返回到全局变量 jQuery。
jQuery 库内部复杂的设计是为了让这个库的扩展和使用变得简单易懂。您可以将自定义函数附加到 jQuery.fn 来添加自己的业务逻辑。并且自定义函数可以像内置函数一样通过包装集调用,例如:
// Define a plugin function Test jQuery.fn.Test = function () { alert("Test"); } // Invoke Test function via jQuery() function jQuery().Test();
摘要
通过理解 jQuery 的工作原理,我们可以更好地掌握这个 JavaScript 库。本文展示的只是 jQuery 库的一个骨架。在掌握了 jQuery 库的基本设计原则和机制后,您可以查看 jQuery 库的原始源代码,了解它是如何利用各种 JavaScript 语言特性来实现简洁性和可扩展性目标的。