日期:2014-05-16  浏览次数:20385 次

JavaScript学习之四 — 点滴之匿名函数

前几天椰子在微博上发了消息说匿名函数也可以有名字,我就想了半天,有名字的匿名函数到底是什么情况??

先来看js中函数的三种定义方式吧:

/**
 * 1、function关键字语句
 */
function fn1(){
	alert("fn1");
}
/**
 * 2、函数字面量(Function Literals)
 */
var fn2 = function(){
	alert("fn2");
};
/**
 * 3、Function构造函数型
 */
var fn3 = new Function('x','alert("fn3:"+x)');
fn1();
fn2();
fn3(3);

其中2函数字面量和3Function构造函数型都是匿名函数,但是两者有区别:

1、函数字面量可以有名字,而Function不能有

?

/**
 * 这就是匿名函数,fn4是匿名函数的名字;<br>
 * 但是fn4只能在函数内调,在外部调会报function is not defined
 * 
 * @param {int}
 *            x
 * @return {Number}
 */
var fn5 = function fn4(x) {
	if (x <= 0)
		return 1;
	return x * fn4(x - 1);
};
alert(fn5(5));
// 此处会报错:fn4 is not defined
alert(fn4(4));

?

?当然此处的递归可以用arguments.callee代替,而且很多书上都推荐用arguments.callee,因为函数名可能是改变的。

?

/**
 * 用arguments.callee代替匿名函数的名字实现递归
 * @param {} x
 * @return {Number}
 */
var fn6 = function (x) {
	if (x <= 0)
		return 1;
	return x * arguments.callee(x - 1);
};
alert(fn6(5));

?

2、Function可以运行时动态的创建和编译js代码,但是Function代码每次运行的时候都会解析函数主题,生成函数对象,循环时候效率很低。

3、Function内变量的作用域是全局作用域

?

var x = 'hello';
/**
 * 此处弹出hello
 */
void function() {
	var x = 'world';
	var fn7 = new Function("alert(x)");
	fn7();
}();

?

?在第一点我们已经看到了匿名函数的名字,一般用作递归,但是如果仅仅用于递归,因为已经有了arguments.callee,是不是显得鸡肋了?

?

进一步,我们来看一下几种匿名函数的代码模式

1、首先来个错误的:

?

/**
 * 语法错误
 */
function (){
	alter("error");
}();

?

2、函数字面量,为什么function外边这个括号很重要?括号里的内容先执行,执行后()所在的地方会被执行结果所替代,结果可能是值、函数,这里是函数

?

/**
 * 字面量函数
 */
(function(){
	alert("literals");
})();

?

3、优先表达式,括号从里到外执行

?

/**
 * 优先表达式
 */
(function() {
	alert("priority");
}());

4、void操作符,void可以执行一个没有圆括号包围的单独的操作数

?

?

/**
 * void操作符
 */
void function(){
	alert("void");
}();

匿名函数有什么好处呢?一次性,即执行一次之后不会放到内存,减少内存占用:

?

/**
 * 在计算过val后内存中一直会保存add函数
 */
function add(x,y){
	return x + y;
}
var val = add(2,3);
alert(val);

/**
 * 在计算出val2之后,内存中不会保存函数
 */
var val2 = function add2(x,y){
	return x + y;
}(2,3);
alert(val2);

/**
 * 在计算出val3之后,内存中也不会保存add3函数。
 */
var val3 = function add3(x,y){
	return x + y;
}(2,3);
alert(val3);

如图:

?

?