JavaScript 嵌套函数(Nested Functions)
在 JavaScript 1.2 以前,函数定义仅允许在高级别的全局代码内,但在 JavaScript 1.2 允许函数嵌套定义在其他函数内。但函数定义仍然有限制,比如不能出现在循环或条件内。不过函数定义的这些限制仅适用于函数声明与函数语句。
匿名函数( function literals,JavaScript 1.2 中引入的另一个功能 ) 可能会出现在 JavaScript 任何表达式中,这意味着他们可以出现在 if 和其它语句内。
示例
请尝试下面的示例,了解如何实现嵌套的函数。
<html>
<head>
<script type="text/javascript">
<!--
function hypotenuse(a, b) {
function square(x) { return x*x; }
return Math.sqrt(square(a) + square(b));
}
function secondFunction(){
var result;
result = hypotenuse(1,2);
document.write ( result );
}
//-->
</script>
</head>
<body>
<p>Click the following button to call the function</p>
<form>
<input type="button" onclick="secondFunction()" value="Call Function">
</form>
<p>Use different parameters inside the function and then try...</p>
</body>
</html>
从上面的例子可以看出,在函数 hypotenuse 嵌套了 square 函数。
匿名函数可以出现在 if 条件语句中,如:
<script type="text/javascript">
if(function(){
return 2;
}) alert(2);
</script>
如果嵌套函数使用了外面函数的变量或者参数,那么这个嵌套函数就形成了一个闭包(Closure)。
闭包能在它外面的函数执行完之后仍然能够访问他外面函数的参数和变量。例如:
function sayGreeting(greeting) {
var prefix = "my friend ";
return function sayGreetingTo(name) {
return greeting + ", " + prefix + name;
}
}
var sayHi = sayGreeting("Hi");
var sayHiToHarry = sayHi("Harry");
console.log(sayHiToHarry); // Hi, my friend Harry
var sayHello = sayGreeting("Hello");
var sayHelloToPeter = sayHello("Peter");
console.log(sayHelloToPeter); // Hello, my friend Peter
在上述代码中,我们用参数"Hi"或者"Hello"调用函数sayGreeting,在函数sayGreeting结束之后,在闭包sayGreetingTo中仍然能够访问参数greeting和变量prefix。
闭包中包含指向外面函数的引用。例如:
function counter (initialValue) {
var privateValue = initialValue;
function changeBy(delta) {
privateValue += delta;
}
return {
increament: function() {
changeBy(1);
},
decreament: function() {
changeBy(-1);
},
getValue: function() {
return privateValue;
}
}
}
var counter1 = counter(5);
var counter2 = counter(5);
counter1.increament();
counter1.increament();
console.log(counter1.getValue()); // 7
counter1.decreament();
console.log(counter1.getValue()); // 6
console.log(counter2.getValue()); // 5
在上面的代码中,3个闭包函数increament、decreament和getValue都嵌套在函数counter里面,都能访问定义在counter里的其他函数以及变量。定义在外面函数中的变量(privateValue)的值能在调用之后得以保存。因此两次调用counter1.increament之后再调用getValue的结果是7。
两次调用counter得到的两个不同对象,它们之间的运行环境(例如counter函数中的变量privateValue等)没有共享。因此在counter1上调用increament或者decreament对counter2没有影响。
上述代码还演示了闭包的一个作用:模拟私有变量和函数。在上述代码中,函数counter中的变量privateValue以及函数changeBy在函数counter之外都不能访问。