在做一个前端页面的时候,引用了一个JQuery插件。它的JS代码大概是这样的:
(function ($) {
"xxx";
$.fn.smartTable = function (options) {
// JQuery Code
};
var settings = $.extend({}, xxx, xxx);
return this.each(function () {
});
}(jQuery));
对于一个JQuery小菜鸟来说当场就蒙逼了,有几个问题:
$.fn.smartTable
又是什么东西?于是开始了我与google的热烈交谈。。
而关于问题1,就是使用了JS的自调用函数(self-invoking function),也可以叫立即调用函数表达式(Immediately-Invoked Function Expression)它通常的形式是这样的:
(function () {
var x = "Hello!!"; // I will invoke myself
})();
一个自调用函数会在定义的时候被自动调用,因为其后面跟着一对括号(方法执行的方式)。
而关于一问题2和4,其实是一种自调用函数的惯常使用方式,而且我们应该坚持使用这种方式。
(function($) {
// all JS code here
})(jQuery);
这里$其实只是一个形参,jQuery就是jQuery的本体对象。把jQuery传递给$其实是方便你使用$符号而不是jQuery关键字。我们也可以使用其它的字符如"j"。($和jQuery的关系详情结尾)
那我们为什么要坚持这种用法呢?
避免冲突,保证这段jQuery可用。
其实这不仅仅是一种使用惯例,而且它保证了你或他人的修改互不影响。假如有人加了下面的代码
var $ = function() {
alert('foo');
}
把非jQuery对象赋值到了$,那么没有重定义$的时候你的脚本就会出错了。
关于上面第一个问题,其实也使用了JS里的闭包(Closure)。定义:A closure is a function having access to the parent scope, even after the parent function has closed. 闭包是一个拥有父范围访问权限的函数,换名话就是,它可以使函数使用其定义外的变量。
Javascript变量有本地和全局访问范围,而闭包可以使全局的变量“变成私有”。
例子1
var a = 4;
function myFunction() {
a = 10;
}
alert(a);
全局变量属于window对象,可以被在其范围内所有的地方使用(类似于类里面的成员变量可以被它的方法所改变)。
P.S. 变量定义时不使用var关键字,总会被视为全局变量,即使它在函数内定义。
P.S. 回想一下上面的闭包定义,其实这里已经是一个简单的闭包了。
例子2
再看一个“复杂点的“闭包:
var iBaseNum = 10;
function addNum(iNum1, iNum2) {
function doAdd() {
return iNum1 + iNum2 + iBaseNum;
}
return doAdd();
}
这里doAdd()除了访问全局变量iBaseNum之外还从父范围里获得了iNum1和iNum2两个变量。(这种嵌套越看越像Java里的子类)
例子3
当我们做计数器的时候,就可以使用全局变量了。
var counter = 0;
function add() {
counter += 1;
}
add();
add();
alert(counter); //这时候显示2
例子4
然而,使用全局变量的话,不仅add()可以改变它的值,其它方式也可以,不安全。而且如果这作为一个文件被别的页面引用的话,容易造成冲突。那如果使用嵌套方法呢?
function add() {
var counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
这时候我们又遇到了另外两个问题:1. 如何调用plus()方法?2. 而且我们还要设法初始化counter变量。
例子5
这时候我们就要引入闭包了。
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// the counter is now 3
例子5就很好解决了前面几个例子遇到的问题:
至于问题3,就是JQuery的技术问题了。
$.fn
是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效。(实际就是使用了prototype,详细可查看jquery.js代码)
如扩展$.fn.abc()
那么你可以这样子:$("#div").abc();
在 jQuery 中,美元符号($)仅仅是 jQuery 的别名,jquery.js里有$=jquery
,就代表了jQuery对象,例如,$("div")
和jQuery("div")
是等价的。
注意两点:
1、即使不使用 $ 也能保证jQuery的所有功能性。
2、为了避免与其他javascript库的冲突,可以释放 jQuery 对 $ 变量的控制,同时为 jQuery 变量规定新的自定义名称。例如:
执行 var jq=$.noConflict();
后,$ 将不再控制当前的jQuery, 而是让渡给了jq变量,此时jq("div")
和 jQuery("div")
是等价的。
向元素附加数据,然后取回该数据:
$("#btn1").click(function(){
$("div").data("greeting", "Hello World");
});
$("#btn2").click(function(){
alert($("div").data("greeting"));
});
平时都是用$(xpath)
但在代码里见到有两个参数的。原来完整的表达式是这样的,jQuery(expression, [context])
返回值:jQuery,而如果指定了 context 参数,如一个 DOM 元素集或 jQuery 对象,那就会在这个 context 中查找,context应该是一个jQuery对象。