在 js 中,函数的定义有两种,一种是函数声明,一种是函数表达式。

函数声明如下:

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

在 js 中,函数的声明是可以在函数的调用后面。也就是说写代码的时候可以先调用,再在后面声明。其中的原因就是 函数声明提升 ,意思就是在执行代码之前,会把所有的函数声明提到前面,优先读取进来,后面就可以调用了。

有些时候,由于函数声明提升,有些程序的执行的效果会跟我们预期的不一样。比如:

//千万不要这么干!
if(condition){
    function sayHi(){
        alert("Hi");
    }
}else{
    function sayHi(){
        alert("Yo");
    }
}

这代码看起来好像没有问题,但是由于函数声明提前会导致函数的声明,这两个声明都会被提升,而且一般情况下是第二条声明会覆盖第一条声明。

如果使用函数表达式就不会有这个问题。

var sayHi;
if(condition){
    sayHi=function(){
        alert("Hi");
    }
}else{
    sayHi=function(){
        alert("Yo");
    }
}

闭包

首先,先来个定义。

闭包是指有权访问另一个函数作用于中的变量的函数。

常见的创建闭包的方式,就是在一个函数内部创建另一个函数。比如:

function outsideFunction(){
    var a=123;
    return function(){
        return a+123;
    }
}

感觉有点像 java 中多重回调的感觉。。。。。

由于内部函数引用了外部函数 outsideFunction() 的 a 变量,所以导致即使 outsideFunction() 被销毁,a 变量还是会留存在内存中,无法释放。如果过多的使用会导致占用过多内存。

如果使用完闭包函数(使用了闭包的函数,暂且怎么称呼吧。。),要释放内存,只需要把这个函数赋值为 null 就可以了。这一点跟 java 还是很相似的。

闭包与变量

由于闭包使用的是引用,也就是说这个值是改变的。这就会导致一个问题。如下:

function createFunction(){
    var result =nuew Array();
    for(var i=0;i<10;i++){
        result[i]= function(){
            return i;
        }
    }
}

返回的一个函数数组,似乎每个函数都会返回自己的索引值,但是,情况不是这样。最后返回的都是 10 。因为闭包的问题,所有返回的函数都是引用的同一个变量,都是 i ,i在最后变成了10 ,也就是所有的引用都变成 10 了。

但是,总有方法的。我们可以在内部包一层,使内部变成一个新的闭包。如下:

function creatFunctions(){
    var result =new Array();
    
    for(var i=o;i<10;i++){
        result[i]=function(num){
            return function(){
                return num;
            }
        }(i);
    }
}

红框中是一个闭包,引用了 num 这个变量,而这个变量通过传参传进来的(蓝色框),函数的传参的有两种,一种是值传递和引用传递,这里的 i 是基本数据类型,所以是值传递。最终就能达到完美想要的效果了。

关于 this 对象

我们在使用 this 的时候,会出现一些问题。我们知道,this 对象是在运行时基于函数的执行环境绑定的。在全局环境中,this 等于 window ,而当函数被作为某个对象的方法调用时,this 等于那个对象。不过匿名对象的执行环境具有全局性。因此其 this 对象通常指向 window。

可以通过 call() 或者 apply() 改变函数执行环境,this 就会指向其他对象。

var name = "The  Window";
var object = {
    name: "My object";
    getnameFunction: function(){
        return function(){
            return this.name;
        }
    }
}
alert(Object.getNameFunc()()); //输出 "The Window"(非严格模式下)

我们可以通过闭包来完成这个操作,就是在外层把 this 赋值给一个对象,然后闭包里面在引用那个对象就行了。在这里就不多讲了。在es6 中可以直接使用 箭头行数来让 this 指向外部函数。