8.2 添加新的全局函数
jQuery内置的某些功能是通过全局函数提供的。所谓全局函数,实际上就是jQuery
对象的方法,但从实践的角度上看,它们是位于jQuery
命名空间内部的函数。
使用这种技术的一个典型的例子就是$.ajax()
函数。$.ajax()
所做的一切都可以通过简单地调用一个名为ajax()
的常规全局函数来实现,但是,这种方式会给我们带来函数名冲突的问题。通过把这个函数放在jQuery
的命名空间内,我们只需避免它与其他的jQuery方法冲突即可。对想要使用插件的人而言,jQuery
命名空间也是一个提醒,即要使用这个插件,必须要有jQuery库。
核心jQuery库提供的很多全局函数都是实用方法;所谓实用方法,就是一些常用功能的快捷方式,但即使手工编写同样功能的代码也不是很难。数组处理方法$.each()
、$.map()
和$.grep()
都是实用方法。为了演示这些实用方法的创建方式,我们再给jQuery核心库添加两个小函数。
要向jQuery
的命名空间中添加一个函数,只需将这个新函数指定为jQuery
对象的一个属性即可参见代码清单8-1。
代码清单8-1
(function($) {
$.sum = function(array) {
//在这里添加代码
};
})(jQuery);
于是,我们就可以在使用这个插件的任何代码中,编写如下代码:
$.sum();
这跟一个基本的调用没什么两样,调用之后就会执行函数体内的代码。
这个求和函数接受一个数组作为参数,然后把数组的值加在一起,最后返回结果。这个插件的代码非常简单,如代码清单8-2所示。
代码清单8-2
- (function($) {
- $.sum = function(array) {
- var total = 0;
- $.each(array, function(index, value) {
- value = $.trim(value);
- value = parseFloat(value) || 0;
- total += value;
- });
- return total;
- };
- })(jQuery);
注意,我们在这里使用了$.each()
方法遍历了数组的值。当然也可以在此使用for
循环,但既然我们能够确定页面会在加载插件之前先加载jQuery库,使用习以为常的语法是很自然的。同样,$.each()
的好处在于它的第一个参数是一个对象。
为了测试这个新插件,我们创建了一个表格,其中包含库存的食品:
<table id="inventory">
<thead>
<tr class="one">
<th>Product</th> <th>Quantity</th> <th>Price</th>
</tr>
</thead>
<tfoot>
<tr class="two" id="sum">
<td>Total</td> <td></td> <td></td>
</tr>
<tr id="average">
<td>Average</td> <td></td> <td></td>
</tr>
</tfoot>
<tbody>
<tr>
<td><a href="spam.html" data-tooltip-text="Nutritious and delicious!">Spam
</a></td> <td>4</td> <td>2.50</td>
</tr>
<tr>
<td><a href="egg.html" data-tooltip-text="Farm fresh or scrambled!">Egg</a>
</td> <td>12</td> <td>4.32</td>
</tr>
<tr>
<td><a href="gourmet-spam.html" data-tooltip-text="Chef Hermann's recipe.">
Gourmet Spam</a></td> <td>14</td> <td>7.89</td>
</tr>
</tbody>
</table>
下载代码示例
如同本书其他HTML、CSS以及JavaScript示例一样,上面的标记只是完整文档的一个片段。如果读者想试一试这些示例,可以从以下地址下载完整的示例 代码: Packt Publishing 网站 http://www.packtpub.com/support ,或者本书网站 http://book.learningjquery.com/。
接下来,我们再写几行脚本,让它负责填写表格中表示数量之和的单元格,参见代码清单8-3。
代码清单8-3
$(document).ready(function() {
var $inventory = $('#inventory tbody');
var quantities = $inventory.find('td:nth-child(2)')
.map(function(index, qty) {
return $(qty).text();
}).get();
var sum = $.sum(quantities);
$('#sum').find('td:nth-child(2)').text(sum);
});
通过浏览器查看HTML页面的结果表明,我们的插件工作正常,如图8-1所示。
图 8-1
添加多个函数
如果我们想在插件中提供多个全局函数,可以独立地声明这些函数。下面,我们再来增强插件,添加一个用于计算数值数组平均值的函数,参见代码清单8-4。
代码清单8-4
- (function($) {
- $.sum = function(array) {
- var total = 0;
- $.each(array, function(index, value) {
- value = $.trim(value);
- value = parseFloat(value) || 0;
- total += value;
- });
- return total;
- };
- $.average = function(array) {
- if ($.isArray(array)) {
- return $.sum(array) / array.length;
- }
- return '';
- };
- })(jQuery);
为了方便起见,我们使用了$.sum()
插件作为辅助,以方便地返回$.average()
的值。同时,为避免出错,这里还检测了传入的参数,在计算平均值之前确保它是一个数组:
好了,现在第二个方法也就绪了,接下我们就用同样的方式来调用它,参见代码清单8-5。
代码清单8-5
$(document).ready(function() {
var $inventory = $('#inventory tbody');
var prices = $inventory.find('td:nth-child(3)')
.map(function(index, qty) {
return $(qty).text();
}).get();
var average = $.average(prices);
$('#average').find('td:nth-child(3)').text(average.toFixed(2));
});
于是,平均值出现了在表格的第三栏,如图8-2所示。
图 8-2
- 扩展全局jQuery对象
事实上,利用$.extend()
函数,还可以通过另外一种语法来定义全局函数,参见代码清单8-6。
代码清单8-6
- (function($) {
- $.extend({
- sum: function(array) {
- var total = 0;
- $.each(array, function(index, value) {
- value = $.trim(value);
- value = parseFloat(value) || 0;
- total += value;
- });
- return total;
- },
- average: function(array) {
- if ($.isArray(array)) {
- return $.sum(array) / array.length;
- }
- return '';
- }
- });
- })(jQuery);
这样调用$.extend()
就可以给全局jQuery对象添加属性(如果原来有相同的属性,就会替换原来的属性)。这样也定义了相同的$.sum()
和$.average()
方法。
- 使用命名空间隔离函数
我们的插件在jQuery命名空间中创建了两个独立的全局函数。但这样写有可能污染命名空间。换句话说,其他jQuery插件也可能定义相同的函数名。为了避免冲突,最好的办法是把属于一个插件的全局函数都封装到一个对象中,如代码清单8-7所示。
代码清单8-7
- (function($) {
- $.mathUtils = {
- sum: function(array) {
- var total = 0;
- $.each(array, function(index, value) {
- value = $.trim(value);
- value = parseFloat(value) || 0;
- total += value;
- });
- return total;
- },
- average: function(array) {
- if ($.isArray(array)) {
- return $.mathUtils.sum(array) / array.length;
- }
- return '';
- }
- };
- })(jQuery);
这个模式的本质是为所有的全局函数又创建了一个命名空间,叫做jQuery.mathUtils
。虽然我们还称它们为全局函数,但实际上它们已经成了 mathUtils
对象的方法了,而mathUtils
对象则保存在jQuery
对象的属性中。结果,在调用它们时就必须得加上插件的名字了:
$.mathUtils.sum(sum);
$.mathUtils.average(average);
使用这种技术(以及足够独特的命名空间),就能够避免全局函数污染命名空间。至此,我们已经掌握了开发插件的基本方法。在把这些函数保存到名为jquery.mathutils.js的文件中之后,就可以将其包含在其他页面中通过其他脚本来使用这些函数了。
选择命名空间
对于仅限于个人使用的函数,一般来说还是把它保存在项目的命名空间中最方便。换句话说,不要保存在jQuery
命名空间中,而要选择一个我们自己的全局对象。比如说,可以将 ljQ
作为全局对象,那么 $.mathUtils.sum()
和 $.mathUtils.average()
就要写成 ljQ.mathUtils.sum()
和 ljQ.mathUtils.average()
了。这样,就可以彻底避免自定义的插件方法与第三方插件方法发生命名冲突。
我们已经介绍了如何保护命名空间,以及确保jQuery插件假定的库的有效性。不过,这些都还是组织上的好处。要想真正体验到jQuery插件的威力,还需要学会为个别jQuery对象实例创建新的方法。