递归
function factorial (num) {
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
问题:上述代码在严格模式下有问题,因为严格模式下不能通过脚本访问arguments.callee。不过,可以借助于命名函数表达式,如下:
var factorial = (function f(num){
if (num <= 1) {
return 1;
}else{
return num * f(num - 1);
}
});
闭包
闭包指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数
function createComparisonFuction(propertyName){
return function(obj1,obj2){
var val1 = obj1[propertyName];//有权访问另一个函数作用域中的变量
var val2 = obj2[propertyName];//有权访问另一个函数作用域中的变量
if(val1 < val2){
return -1;
}else if(val1 > val2){
return 1;
}else{
return 0;
}
}
}
即使内部函数被返回了,而且在别的地方被调用,仍然可以访问变量propertyName。因为内部函数的作用域链中包含外部函数createComparisonFunction()的作用域。
var compare = createComparisonFunction("name");
var result = compare({name:"sqliang"},{name:"zcy"});
调用compare的过程产生作用域链的关系:
一般来讲,函数执行完毕后,局部活动对象会销毁,但是闭包情况不同,在另一个函数内部定义的函数会将包含函数的活动对象添加到自己的作用域链中。因此,因此包含函数的活动对象依然存在,由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存
注意:闭包只能取得包含函数中任何变量的最后一个值,闭包所保存的是整个变量对象,而不是某个特殊的变量
function createFuction () {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function(){
return i;
}
}
return result;
}
以上代码每个函数都返回10。因为每个函数的作用域链中都保存着createFunction()函数的活动对象,所以,他们引用的都是同一个变量。
function createFuction () {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function(num){
return num;
}(i);
}
return result;
}
修改后每个函数就会返回各自不同的索引值了。没有直接把闭包赋值给数组而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给数组。在调用匿名函数时,传入了变量i,由于函数参数是按值传递的,所以就会将当时的i值复制给参数num。
var name = "the window";
var obj = {
name : "my obj",
getName : function(){
return function(){
this.name;
}
}
}
//匿名函数的执行通常具有全局性,因此其this通常指向window,在通过call或apply改变函数执行环境的情况下,this就会指向其他对象
console.log(obj.getName()());//the window
有的时候,在定义匿名函数之前,把this对象赋值给一个名叫that的变量。在定义了必报后,闭包就可以访问这个变量。
var name = "the window";
var obj = {
name : "my obj",
getName : function(){
var that = this;
return function(){
that.name;
}
}
}
console.log(obj.getName()());//my obj
模仿块级作用域
匿名函数可以用来模仿块级作用域,语法如下:
(function(){
//...codes 块级作用域
})();
定义并立即调用了一个匿名函数。将函数声明放在括号里表示他实际上是一个函数表达式
function outputNum(count){
(function(){
for (var i = 0; i < count; i++) {
console.log(i);
};
})();
console.log(i);//导致一个错误
}
这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。另外,这种做法可以较少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就可以立即销毁其作用域链了
(function(){
var now = new Date();
if (now.getMonth() == 0 && now.getDate() == 1) {
console.log("Happy new year");
}
})();