在 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 指向外部函数。