假期来复习一下JavaScript,先从递归和闭包开始。

1.函数的声明方式有两种,一是函数声明,一是函数表达式。

1
2
3
4
function sayHi(){
alert("Hi");
}
sayHi();
1
2
3
4
var sayHi = function(){
alert("Hi");
}
sayHi();//错误:函数不存在

2.递归
一个简单的递归阶乘函数

1
2
3
4
5
6
7
8
9
10
function factorial (num){
if(num <=1 ){
return 1;
} else {
return num * factorial (num-1);
//return num * arguments.callee (num-1);
//使用arguments.callee 比函数名更保险
//but 严格模式下此属性被禁用
}
}

arguments.callee是一个指向正在执行函数的指针,可以利用它实现对函数的递归调用
或者采用命名函数表达式的方法

1
2
3
4
5
6
var factorial = (function f (num){
if(num <=1 ){
return 1;
} else {
return num * f (num-1);
})

将命名为f() 的函数表达式赋值给 factorial,即使函数赋值给另一变量,递归也能正常的进行

3.闭包
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数。
在调用每个匿名函数时,立刻执行该匿名函数的结果赋值给数组。由于函数参数是按值传递的,因此就会将变量i的当前值赋值给参数num

1
2
3
4
5
6
7
8
9
10
11
12
function createFunction(){
var result = new Array();
for(var i=0 ; i<10 ;i++){
result[i] = function (num) {
return funtion(){
return num;
}
}(i);
}
return result;
}

一个有趣的例子

1
2
3
4
5
6
7
8
9
10
11
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。
而在 add10 中,x 则为 10。

4.关于this

1
2
3
4
5
6
7
8
9
10
11
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window"

内部函数永远不可能直接访问到外部函数的argument对象和this对象,因此返回了全局name变量的值。
如果把外部作用域中的this对象保存在一个闭包可以访问的变量中,就可以让闭包访问该对象了~

1
2
3
4
5
6
7
8
9
10
11
var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
alert(object.getNameFunc()());//“The Object”

5.块级作用域
用作块级作用域的匿名函数的语法如下:

1
2
3
( function( ) {
//code
}) ( );

无论在什么地方,只要临时需要一些变量,就可以使用私有作用域。

1
2
3
4
5
6
7
8
function outputNumbers ( count ) {
(function () {
for( var i=0; i <count ;i++){
alert(i);
}
})( );
alert(i); // i is not defined
}

6.用闭包模拟私有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); //0
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); //2
Counter1.decrement();
console.log(Counter1.value()); //1
console.log(Counter2.value()); //0

两个计数器是有各自的独立性的。每次调用 makeCounter() 函数期间,其环境是不同的。
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures