函数表达式
定义函数有两种方式:函数声明和函数表达式。
函数声明
Firefox、Safari、Chrome、Opera支持函数的非标准属性name
,这个属性的值总等于function
关键字后面的标识符。
函数声明的一个重要特征就是函数声明提升。
1 2 3 4
| sayHi(); function sayHi(){ console.log('Hi!'); }
|
函数表达式
函数表达式的最常用形式:
1 2 3
| var functionName = function(){ }
|
函数表达式在使用时必须先赋值,下面代码就会导致错误:
1 2 3 4
| sayHi(); var sayHi = function(){ console.log('Hi!'); }
|
这样是不行滴
1 2 3 4 5 6 7 8 9 10
| if(condition){ function sayHi(){ console.log('Hi!'); } } else{ function sayHi(){ console.log('Yo!'); } }
|
以上代码并不会像我们想象的那样根据condition
的值来返回不同的函数声明,而是在不同的浏览器之间有着不同的实现。大多数浏览器会返回第二个声明,而忽略condition
;Firefox会在condition
为true时返回第一个声明。由于表现的不一致,最好不要这么干(小伙子你在玩火你知道吗?)。
改成函数表达式就行了
1 2 3 4 5 6 7 8 9 10 11
| var sayHi if(condition){ sayHi = function (){ console.log('Hi!'); }; } else{ sayHi = function (){ console.log('Yo!'); }; }
|
作为函数返回值的匿名函数
既然函数可以作为值赋给变量,也就可以作为函数的返回值而存在,就像下面这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function createComparisonFunction(propertyName){ return function(obj1,obj2){ var value1 = obj1[propertyName]; var value2 = obj2[propertyName];
if(value1 < value2){ return -1; } else if(value1 > value2){ return 1; } else{ return 0; } }; } var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
data.sort(createComparisonFunction('name')); console.log(data[0].name);
data.sort(createComparisonFunction('age')); console.log(data[0].name);
|
递归
经典递归
递归函数是在一个函数通过名字调用自身的情况下构成的,来看下面这个经典的递归函数:
1 2 3 4 5 6 7 8 9
| function factorial(num){ if(num <= 1){ return 1; } else{ return num * factorial(num-1); } } factorial(5);
|
解耦和
上面的例子是跟函数名挂钩的,如果函数名被清空了,就会出现问题:
1 2 3
| var factorial2 = factorial; factorial = null; factorial2(5);
|
可以使用argument.callee
来解除这种耦合,因为arguments.callee
指向拥有这个arguments
对象的函数:
1 2 3 4 5 6 7 8 9 10 11 12
| function factorial(num){ if(num <= 1){ return 1; } else{ return num * arguments.callee(num-1); } }
var factorial2 = factorial; factorial = null; factorial2(5);
|
严格模式下的递归
由于arguments.callee
在严格模式下访问会导致出错,所以严格模式下,就得换一种思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var factorial = (function f(num){ if(num <= 1){ return 1; } else{ return num * f(num-1); } });
var factorial2 = factorial; factorial = null; factorial2(5);
|
上面的示例代码把一个名为f()的命名函数表达式赋值给了变量factorial
,之后即使把这个函数赋值给另一个变量,函数名f仍然有效。可以看到代码中最后一行无法对f进行赋值操作。因为与函数声明不同的是,函数表达式中的命名函数的函数名并不是一个变量。关于这一点,可以看下面这个例子:
1 2 3 4 5 6 7 8 9 10
| function fn1(){ console.log('fn1'); }
var fn = function fn2(){ console.log('fn2'); }
console.log(fn1); console.log(fn2);
|
喵了个喵~