函数表达式
定义函数有两种方式:一种是函数声明,另一种就是函数表达式
//1,函数声明
function functionName(arg0, arg1, arg2){
//函数体
}
//函数声明的一个重要特征是,函数声明提升,意思是在执行代码之前会先读取函数声明。而函数表达式没有这个特征。
eg: sayHi();
function sayHi(){
alert('Hi!');
}
//2,函数表达式
var functionName = function(arg0, arg1, arg2){
//函数体
}
1. 递归
在非严格模式下使用arguments.callee
,它是一个指向正在执行的函数的指针,可以用它来代替函数名实现对函数的递归调用。在严格模下可以使用命名函数表达式来达到相同的结果。
function factorial(num){
if(num <=1){
return 1;
}else{
return num * factorial(num-1);
}
}
//非严格模式
function factorial(num){
if(num <=1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
//严格模式
var factorial = {
function f(num){
if(num <=1){
return 1;
}else{
return num * f(num-1);
}
}
2. 闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式是在一个函数内部创建另一个函数。
2.1 关于this对象
在全局函数中,this等于window。
var name = 'the window';
var obj = {
name : 'the obj',
getNameFunc : function(){
return this.name;
}
}
alert(obj.getNameFunc()); //'the obj'
alert((obj.getNameFunc)()); //'the obj'
alert((obj.getNameFunc = obj.getNameFunc)()); //'the window'
var name = 'the window';
var obj = {
name : 'the obj',
getNameFunc : function(){
return function(){
return this.name;
}
}
}
alert(obj.getNameFunc()()); //'the window'
//把this对象保存在闭包中的另一个可以访问到的变量中。
var name = 'the window';
var obj = {
name : 'the obj',
getNameFunc : function(){
var that = this;
return function(){
return that.name;
}
}
}
alert(obj.getNameFunc()()); //'the obj'
3. 模仿块级作用域
JS没有块级作用域,但是可以将语句块包含在函数中模仿块级作用域。
var someFunc = function(){
//函数体,这里是块级作用域
};
someFunc(); //函数后面加括号,表示立即调用执行。但是只是针对函数表达式。
function(){
//函数体,这里是块级作用域
}(); //出错,函数声明后面不能跟圆括号,但是可以给函数声明加上一对圆括号,表示将函数声明转换成函数表达式,如下所示。
(function(){
//函数体,这里是块级作用域
})();
4. 私有变量
任何在函数中定义的变量,都可以认为是私有变量。我们把有权访问私有变量和私有函数的公有方法称为特权方法。有两种方法创建特权方法。
//方法一:在构造函数中定义特权方法
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){
name = value;
};
}
var person1 =new Person('dan');
var person2 =new Person('jun');
alert(person1.getName()); //'dan'
alert(person2.getName()); //'jun'
//方法二:在私有作用域中定义私有变量或函数,同样也可以创建特权方法
(function(){
//私有变量和私有函数
var name = ''; //私有变量name在这种模式下变成了一个静态的,由所有实例共享的属性
//初始化未经声明的变量,会创建一个全局变量
Person = function(value){
name = value;
};
//公有/特权方法
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function(value){
name = value;
};
})();
var person1 = new Person('dan');
alert(person1.getName()); //'dan'
person1.setName('jun');
alert(person1.getName()); //'jun'
var person2 = new Person('jenny');
alert(person1.getName()); //'jenny'
alert(person2.getName()); //'jenny'
4.1 模块模式
前面的模式都是用于为自定义类型创建私有变量和特权方法,而模块模式则是为单例创建私有变量和特权方法。所谓单例,指的就是只有一个实例的对象,按照惯例,JS以对象字面量的方式来创建单例对象。
var singleton = function(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//特权/共有方法和属性
return {
publicProperty: true,
publicMethod: function(){
privateVariable++;
return privateFunction();
}
}
}
简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。