欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript 函数表达式 闭包

程序员文章站 2022-03-18 19:14:33
...

创建函数有两种方式:一种是函数声明,另一种是函数表达式


1.函数声明

function functionName(i,j){
    //函数体
}

说明:首先是函数关键字function,然后是函数的名字functionName
最大的特征:函数声明提升,这就意味着函数声明可以放在调用它的语句之后

sayHi();//函数调用在前
function sayHi(){//函数声明在后
    alert("hi");
}

2.函数表达式

最常见的方式如下:

var functionName=function(i,j){
    //函数体
}

说明:形式很像变量赋值语句,即创建一个函数并将它赋给变量functionName。这种情况下创建的函数叫做匿名函数(也叫拉姆达函数),因为function关键字后面没有标识符。
重要特征:必须先声明再调用。

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

闭包

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

function createComparsionFunction(propertyName){
    return function(object1,object2){
    //这是一个闭包,不能简单认为匿名函数就是闭包
        var value1=object1[propertyName];
        var value2=object2[propertyName];
        if(value1<value2){
            return -1;
        }
        else if(value1>value2){
            return 1;
        }
        else{
            return 0;
        }
    ;
}
//创建函数
var compareNames=creatComparsionFunction("name");
//调用函数
var result=compareNames({name:"Nicholas"},{name:"Greg"});
//解除对匿名函数的引用(以便释放内存)
compareNames=null;

说明:在匿名函数从createComparsionFunction()中被返回后,它的作用域被初始化为包含 createComparsionFunction()函数的活动对象和全局变量对象。
更重要的是: createComparsionFunction()函数在执行完毕后,它的活动对象也不会被销毁!!!,因为匿名函数的作用域链仍然在引用这个活动对象。
换句话说:当createComparsionFunction()函数返回后,其作用域链被销毁,但其活动对象仍然在内存中,直到匿名函数被销毁之后才销毁。
通过compareNames=null,解除该函数的引用,等于通知垃圾回收例程将其回收。随着匿名函数的作用域链被销毁,其他作用域(除了全局作用域)也都可以安全的销毁了。
JavaScript 函数表达式 闭包

  • 闭包的副作用:即闭包只能取得包含函数(外部函数)中任何变量的最后一个值,注意哦是最后一个!!!
function createFunctions(){
    var result=new Array();
    for (var i=0; i<10; i++){
        result[i]=function(){//这是一个闭包,也是匿名函数
            return i;
        };
        //result[]里面保存的都是10,而不是期望的索引值0到9.
        //什么情况看后面!!!
    return result;
}

**解释:每个匿名函数的作用域链中都保存这createFunction()函数的活动对象。就像其前面所说的当createFunction()函数返回后,其作用域链被销毁,但其活动对象仍然在内存中,直到匿名函数被销毁之后才销毁。 它返回之后i=10。而每个函数都引用了保存这个变量i的活动对象,所以每个函数的内部都是10

  • 解决方法:创建另一个匿名函数强制让闭包的行为符合预期

function createFunctions(){
    var result=new Array();
    for (var i=0; i<10; i++){
        result[i]=function(num){
        //再创建一个匿名函数,有一个参数num
        //每次调用时都将变量i的当前值赋给参数num
            return function(){
            //创建一个返回num的闭包
                return num;
            };
        }(i);//每次调用时都将变量i的当前值赋给参数num
        //这样result[]中的每个函数都有自己num变量的一个副本,因此能返回各个不同的值
    }
        //result[]里面保存的是期望的索引值0到9.
    return result;
}
  • 闭包中的this对象
    我们知道this对象在运行时基于函数的执行环境绑定的:在全局函数中,this等于window对象。而当函数被作为某个对象的方法调用时,this等于那个对象。
    不过匿名函数的执行环境具有全局性,因此this对象通常指向window对象
var name="The Window",
var object={
    name:"my boject";
    getNameFunction:function(){
        return function(){
            rerurn this.name;
        };
    }
}
alert(object.getNameFunction()());//The Window
//object.getNameFunction()返回一个函数
//object.getNameFunction()()立即调用返回的这个函数

解决:将外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问这个对象了

var name="The Window",
var object={
    name:"My Object";
    getNameFunction:function(){
        var that=this;//外部的this对象保存在that中
        return function(){
            rerurn that.name;//而不是this.name
        };
    }
}
alert(object.getNameFunction()());//My Object