函数表达式

一.定义函数

定义函数的两种方式:函数声明和函数表达式

1.函数声明

function functionName(arg0,arg1,…){

    //函数体

}

①name属性:访问函数的名字

alert(funcitonName.name);//”functionName”

②函数声明提升

在代码执行之前会先读取函数声明(解析器会率先读取函数声明)。所以函数声明可以放到调用它的语句后边

2.函数表达式:创建函数再赋值给变量

var functionName=function(arg0,arg1,…){

    //函数体

};

①函数声明要求有名字,但函数表达式不需要。没有名字的函数表达式叫匿名函数

②没有函数声明提升,所以使用前先赋值

sayName(); //出错

var sayName=function(){

    alert(“liuzhongyi”);

};

③在控制语句中应该使用函数表达式,而不是函数声明

④使用匿名函数可以将函数当做值来使用,将函数作为其他函数的返回值等

二.递归

递归函数:一个函数通过名字调用自身

但使用函数名调用自身时,只要函数名变化,递归函数将出现问题

①使用arguments.callee来调用自身:是一个指针,指向正在执行的函数

function myFunction(num){
    if(num<=1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

②使用函数表达式

var myFunction=(function f(num){
    if(num<1){
        return 1;
    }else{
        return num*f(num-1);
    }
});

即使将myFunction改名,f(num)依然能在函数内使用

三.闭包

闭包:有权访问另一个函数作用域中的变量 的函数

创建闭包:在函数内部创建另一个函数

1.闭包原理

①执行环境和作用域链

QQ截图20131205235823

作用域链本质是一个指向变量对象的指针列表,只引用但不实际包含变量对象

当函数执行完毕后,执行环境,作用域链及局部变量对象就会销毁,内存中只保存全局作用域(全局变量对象)

②在一个函数内部定义的匿名函数将外部函数的活动对象(局部变量对象)添加到它的作用域链中

这个匿名函数被返回后,它的作用域链被初始化为包含它自己的作用域,包含函数的作用域和全局作用域

函数在执行完毕后,其活动对象也不会销毁,因为匿名函数的作用域链依然在引用这个活动对象

解除匿名函数的引用,活动对象被销毁 myFunction=null;

2.闭包与变量

闭包只能取得包含函数中任何变量的最后一个值      //没看懂

3.关于this对象

this对象是与函数运行时的执行环境绑定的,全局函数中this等于window,当函数作为某个对象的方法调用时,this等于那个对象

var name="window";
var object={
    name:"object",
    getThis:function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getThis()); //"window" 因为this能够访问到全局变量中的name变量

this不能指向自己吗??

var name="window";
var object={
    name:"object",
    getThis:function(){
        return this.name;
    }
};
(object.getThis=object.getThis)(); //"window"
4.内存泄漏
闭包的作用域链中保存着一个HTML元素,那么该元素将无法被销毁
因为BOM,COM对象是以COM对象的形式实现的,采用的是引用计数的垃圾收集策略,由于闭包的存在,HTML元素的引用次数至少是1,所以不能被收回
四.模仿块级作用域
function outputNumbers(count){
    for(var i=0;i<count;i++){
        alert(i);
    }

var i;
alert(i); //依然计次
}

Java,C中i只会在for循环的语句块中有定义,循环一结束,变量i就会被销毁。但JS中没有块级作用域,i定义在outputNumbers()的活动对象里,而且会对后续的再次声明视而不见

1.私有作用域:用匿名函数模仿块级作用域

function关键字表示函数声明的开始,将函数声明转换成函数表达式,只要给它加上一对圆括号。函数表达式可以直接作为值来取代函数名。调用函数就是在后边加一对圆括号

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

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

function outputNumbers(count){
    (function(){
        for(var i=0;i<count;i++){
            alert(i);
        }
    })();
alert(i); //出错
}

好处:

①私有作用域,每个开发人员都可以定义自己的变量,而不用担心扰乱全局作用域

②可以减少闭包占用的内存,因为没有指向匿名函数的引用,函数执行完作用域链就可以销毁

2.私有变量

所有对象属性都是公有的。(可以在外部访问对象属性)

私有变量:函数的参数,局部变量,函数内部定义的其他函数。在函数外部不能访问这些变量

公有方法:可以通过闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量

特权方法:有权访问私有变量的方法叫特权方法

自定义类型的特权方法

①在构造函数中定义特权方法

function Person(name){
    this.getName=function(){
        return this.name;
    };
    this.setName=function(value){
        this.name=value;
    };
}
var person1=new Person("liu");
alert(person1.getName());// "liu"
person1.setName("zhong");
alert(person1.getName()); //"zhong"

实现了在构造函数外部访问了私有变量name

缺点:构造函数的弊端,每个实例都会创建同一组相同的方法

②静态私有变量

(function(){
    var name="";
    Person=function(value){   //声明全局变量,使用函数表达式,因为函数声明只能创建局部函数
        name=value;
    };
    Person.prototype.getName=function(){
        return name;
    };
    Person.prototype.setName=function(){
        name=value;
    };
})();

var person1=new Person("liu");
alert(person1.getName()); //"liu"
person1.setName("zhong");
alert(person1.getName());

在一个函数上调用私有变量会影响所有实例,每个实例没有自己的私有变量

单例的特权方法

①模块模式

为单例(只有一个实例的对象)创建私有变量和特权方法

当必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,就可以使用模块模式

var application=function(){
    //私有变量和函数    
    var components=new Array();
    //初始化
    components.push("liu");
    //公有方法
    return{
        getLength:function(){
            return components.length;    
        }
    }; 
}();

②增强的模块模式

单例必须是某种类型的实例,同时还必须添加某些属性和方法对其以增强的情况

//application对象必须是BaseComponent的实例
var application=function(){
    //私有变量和函数
    var components=new Array();
    //初始化
    components.push(new BaseComponent());
    //创建application的一个局部副本
    var app=new BaseComponent();
    //公共接口
    app.getLength=funtion(){
         return components.length;
    };
    //返回这个副本
    return app;
}();
原文地址:https://www.cnblogs.com/liuzhongyi1992/p/3473006.html