js高级程序设计笔记3(函数表达式)

定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。

//函数声明的语法是这样的
function functionName(arg0, arg1, arg2) {//函数体} ```

//函数表达式有很多种,最常见的的语法是这样的
var functionName = function(arg0, arg1, arg2){//函数体}; ```

一、递归

function factorial(num){
    if (num <= 1){
        return 1;
    } else {
        return num * factorial(num-1);
    }
}```
这是一个经典的递归阶乘函数。虽然这个函数表面看来没什么问题,但下面的代码却可能导致它出错。

var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4)); //出错! ```
arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用,例如:

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);
}
});```
以上代码创建了一个名为 f()的命名函数表达式,然后将它赋值给变量 factorial。即便把函数赋值给了另一个变量,函数的名字 f 仍然有效,所以递归调用照样能正确完成。这种方式在严格模式和非严格模式下都行得通。

二、闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数

1. 闭包与变量
function createFunctions(){
    var result = new Array();
    for (var i=0; i < 10; i++){
        result[i] = function(){
                return i;
        };
    }
    return result;
} //返回数组内部是十个10```

function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
} //返回数组内容是0-9```

2. 关于this对象
var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getNameFunc()()); //"The Window"(在非严格模式下) ```
每个函数在被调用时都会自动取得两个特殊变量: this 和 arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,永远不可能直接访问外部函数中的这两个变量。不过,把外部作用域中的 this 对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了,如下所示。 

var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object" ```

3. 模仿块级作用域

JavaScript 没有块级作用域的概念。这意味着在块语句中定义的变量,实际上是在包含函数中而非语句中创建的

function outputNumbers(count){
    for (var i=0; i < count; i++){
        alert(i);
    }
    alert(i); //计数
}```
这个函数中定义了一个 for 循环,而变量 i 的初始值被设置为 0。在 Java、 C++等语言中,变量 i只会在 for 循环的语句块中有定义,循环一旦结束,变量 i 就会被销毁。可是在 JavaScrip 中,变量 i是定义在 ouputNumbers()的活动对象中的,因此从它有定义开始,就可以在函数内部随处访问它。 
在一个由很多开发人员共同参与的大型应用程序中,过多的全局变量和函数很容易导致命名冲突。而通过创建私有作用域,每个开发人员既可以使用自己的变量,又不必担心搞乱全局作用域。例如:

(function(){
var now = new Date();
if (now.getMonth() == 0 && now.getDate() == 1){
alert("Happy new year!");
}
})(); ```

4. 私有变量

增强的模块模式

var singleton = function(){
    //私有变量和私有函数
    var privateVariable = 10;
    function privateFunction(){
        return false;
    }
    //创建对象
    var object = new CustomType();
    //添加特权/公有属性和方法
    object.publicProperty = true;
    object.publicMethod = function(){
        privateVariable++;return privateFunction();
    };
    //返回这个对象
    return object;
}(); ```

推荐阅读更多精彩内容

  • 定义函数的方式有两种:函数声明和函数表达式。 函数声明的一个重要特征就是函数声明提升,意思是在执行代码前会先读取函...
    oWSQo阅读 95评论 0 0
  • 继承 一、混入式继承 二、原型继承 利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的...
    magic_pill阅读 420评论 0 3
  • 定义函数的方式有两种:一种是函数声明,另一种是函数表达式。函数声明的语法是这样的。 说明:Firefox、Safa...
    yjaal阅读 37评论 0 1
  • 第5章 引用类型 引用类型的值(对象)是引用类型的一个示例。在ECMAScript 中,引用类型是一种数据结构,用...
    力气强阅读 204评论 0 0
  • 人多上电梯(斜梯),电梯的右边都站满了人,无意中站到了左边,前面看看没有站,往后一看,好多人顺着电梯左边往上走,...
    非常可阅读 23评论 0 0