文章目录

    • 自调用方法
    • 闭包
      • 为什么我们需要闭包?
    • 扩展jQuery
      • 向元素附加数据
      • 两个参数的jQuery


在做一个前端页面的时候,引用了一个JQuery插件。它的JS代码大概是这样的:

(function ($) {
	"xxx";
	$.fn.smartTable = function (options) {
		// JQuery Code
	};
	var settings = $.extend({}, xxx, xxx);
	return this.each(function () {
	});
}(jQuery));

对于一个JQuery小菜鸟来说当场就蒙逼了,有几个问题:

  1. 最外层的括号有什么作用?
  2. function里的美元符号是什么意思?
  3. $.fn.smartTable又是什么东西?
  4. 最后的(jQuery)又是在干什么?

于是开始了我与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就很好解决了前面几个例子遇到的问题:

  1. 需要注意的是这里使用了自调用函数,从而解决了counter的初始化。
  2. 用于计数的自调用函数返回并赋值到了add变量里,从而使函数可以被外界所访问
  3. 而实现了以上功能之外,闭包可以使本该作为全局变量的计数器counter被匿名方法保护着“变成了私有”,不会被其它方式所改变

扩展jQuery

至于问题3,就是JQuery的技术问题了。
$.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效。(实际就是使用了prototype,详细可查看jquery.js代码)
如扩展$.fn.abc()
那么你可以这样子:$("#div").abc();

其它这个文件学到的东西

关于美元符号($)与jQuery对象

在 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"));
});

两个参数的jQuery

平时都是用$(xpath)但在代码里见到有两个参数的。原来完整的表达式是这样的,jQuery(expression, [context]) 返回值:jQuery,而如果指定了 context 参数,如一个 DOM 元素集或 jQuery 对象,那就会在这个 context 中查找,context应该是一个jQuery对象。

更多推荐

JQuery闭包与自调用方法