Javascript高级程序设计 第七章 --- 函数表达式

定义函数的方式有两种:

  • 函数声明
  • 函数表达式

函数声明的语法

function funtionName(arg0, arg1, arg2){
    // 函数体
}

关于函数声明,他有一个重要特征就是函数声明提升,就是在执行代码之前会读取函数声明。

sayHi();
function sayHi(){
    alert("hi!");
}

函数表达式

var functionName = function(arg0, arg1, arg2){
    // 函数体
};

这种形式的看起来像常规的变量赋值语句,即创建一个函数并将它赋值给变量,这时候也叫匿名函数
函数表达式,在使用前必须先赋值。

sayHi();    // 错误,函数不存在
var sayHi = function(){
    alert("sayHi");
}

递归

递归函数是在函数通过名字调用自身情况下构成的:

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代替函数名,无论如何也不会出问题。


闭包

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

function createComparisonFunction(propertyName){
    return function(object1, object2){
        var value1 = object[propertyName];
        var value2 = object[propertyName];

        if(value1 < value2){
            return -1;
        } else if (value1 > value2){
            return 1;
        } else{
            return 0;
        }
    }
}

闭包与变量

根据作用域链的匹配机制,闭包只能取得包含函数中任何变量的最后一个值。闭包保存的是整个变量对象,而不是特殊的变量。

function createFunction(){
    var result = new Array();
    for(var i=0; i < 10; i++){
        result[i] = function(){
            return i;
        };
    }
    // for语句中创建的变量i即使在for循环结束,也依旧存在于循环外部的执行环境
    return result;
}

这个函数会返回一个数组,表面上看,似乎每个函数都应该返自己的索引值,即位置0返回0,位置1返回1。实际上,每个函数都返回10。
因为每个函数的作用域链中都保存着 createFunctions()函数的活动对象,所以他们都引用同一个变量i。当createFunctions()函数返回后,变量i的值是10,因此每个函数都饮用者保存变量i的同一个变量对象,所以在每个函数内部i都是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;
}

关于 this对象

在全局函数中,this等于 window,当函数作为每个对象调用时,this等于那个对象。
匿名函数的执行环境具有全局性,因此其 this对象通常指向 window。

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

可以通过外部作用域中的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"

或者修改代码,也可以访问到 “My Object”:

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

模仿块级作用域

用作块级作用域(通常称为私有作用域)的匿名函数语法如下:

(function(){
    // 块级作用域
})();

以上定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。紧跟着一个括号会立即调用这个函数。通过创建私有作用域,开发人员既可以使用自己的变量,又不必担心搞乱全局变量。

在匿名函数中定义的任意变量,都会在执行结束时被销毁。


私有变量

任何在函数中定义的变量,都可以认为是私有变量,因为不能再函数外部访问这些变量。
私有变量包括函数的参数 局部变量 和在函数内部定义的其他函数。

我们把有权访问私有变量和私有函数的公有方法称为特权方法。

function MyObject(){
    // 私有变量和私有函数
    var privateVariable = 10;
    function privateFunction(){
        return false;
    }

    // 特权方法
    this.publicMethod = function(){
        privateVariable ++;
        return privateFunction();
    }
}

利用私有和特权成员,可以隐藏那些不该被直接修改的数据,

function Person(name){
    this.getName = function(){
        return name;
    };
    this.setName = function(value){
        return name = value;
    }
};

var person = new Person("Lyf");
alert(person.getName());        // "Lyf"
person.setName("JackLiu");
alert(person.getName());    // "JackLiu"

静态私有变量

通过私有作用域中定义私有变量或函数,同样也可以创建特权方法

(function(){
    // 私有变量和私有函数
    var privateVariable = 10;
    function privateFunction(){
        return false;
    };

    // 构造函数
    MyObject = function(){
    };

    // 公有/特权方法
    MyObject.prototype.publicMethod = function(){
        privateVariable ++;
        return privateFunction();
    };
})();

这个模式与在构造函数中定义特权方法的主要区别,就在于私有变量和函数是由实例共享的。由于特权方法是在原型定义的,因此所有实例使用同一个函数。

(function(){
    var name = "";
    Person = function(value){
        name = value;
    };         // 注意这里的构造函数是全局的,可以在闭包外访问
    Person.prototype.getName = function(){
        return name;
    };
    Person.prototype.setName = function(value){
        name = value;
    }
})();

var person1 = new Person("Lyf"); 
alert(person1.getName());       // "Lyf" 
person1.setName("JackLiu");     
alert(person1.getName());       // "JackLiu"

var person2 = new Person("Mike");
alert(person1.getName());       // "Mike"
alert(person2.getName());       // "Mike"

在这种模式下,变量name就变成一个静态的、由所有实例共享的属性。也就是说,调用setName()会影响所有实例。

模块模式

前面的模式是用于为自定义类型创建私有变量和特权方法的。
模块模式是为单例创建私有变量和特权方法。
所谓单例,指的是只有一个实例的对象。按照惯例,JavaScript是以对象字面量的方式来创建单例对象。

var singleton = {
    name : value,
    method : function(){
        // 这里是方法代码
    }
};

模块模式通过为单例添加私有变量和特权方法能够使其得到增强:

var singleton = function(){
    // 私有变量和私有函数
    var privateVariable = 10;
    function privateFunction(){
        return false;
    }
    // 特权/公有方法和属性
    return{
        publicProperty : true,
        publicMethod : function(){
            privateVariable ++;
            return privateFunction();
        }
    };
}();

这个模块模式使用了一个返回对象的匿名函数,在这个函数内部,首先定义了私有变量和函数,然后,将一个对象字面量作为函数的返回值。返回的对象字面量中只包含可以公开的属性和方法。从本质上讲,这个对象字面量定义的是单例的公共接口。这种模式需要对单例进行某些初始化,同时又需要维护其私有变量时时非常有用的。比如:

var application = function(){
    // 私有变量和函数
    var components = new Array();
    // 初始化
    components.push(new BaseComponent());

    // 公共
    return {
        getComponentsCount : function(){
            return components.length;
        },
        registerComponent : function(){
            if(typeof component == "object"){
                component.push(component);
            }
        }
    };
}();


增强的模块模式

这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和方法对其加以增强的情况。

var singleton = function(){
    // 私有变量和私有函数
    var privateValue = 10;
    function privateFunction(){
        return false;
    };

    // 创建对象
    var object = new CustomType();

    // 添加特权/公有属性和方法
    object.publicProperty = true;
    object.publicMethod = function(){
        privateVariable ++;
        return privateFunction();
    };

    // 返回这个对象
    return object;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值