首页 > 代码库 > JavaScript作用域、上下文环境、函数对象的定义与调用、匿名函数的定义与调用、闭包

JavaScript作用域、上下文环境、函数对象的定义与调用、匿名函数的定义与调用、闭包

提到闭包总给人很高深的感觉,网上的例子也数不胜数。但是我发现相当一部分并不容易理解。根据我的观察,是因为这些例子把标题中提到的概念糅杂在了一起,往往越看越糊涂。所以我希望化整为零,拆成简单例子来解释。


1.先看作用域:

JavaScript作用域只有两种——全局作用域和函数内作用域,没有代码块作用域。示例:


function loop(){

for(var i=0;i<5;i++){

//doSomething;

}

alert(i); 

}

loop(); //执行函数结果为5。


尽管变量i已经脱离了循环代码块,但因为JavaScript没有代码块级作用域,所以i的作用域是在整个函数内。循环结束后仍然保持为5。当然作为局部变量,函数执行完毕就释放了。


全局作用域就好理解了。变量在整个页面的执行环境下都有效。定义的方法有两种:一是在所有函数外定义的变量即为全局变量;二是定义变量时不加var,此时被认为是全局变量。

例如:

<script>

var i=10; //全局变量

function f1(){

times=3; //全局变量

}

</script>


2.上下文环境与"this"

上下文环境说的是对象(函数)的“继承关系”,而非函数之间的调用关系。函数间的互调用并不改变上下文环境,体现函数间互调用有另外一个变量caller表示。示例:

function a(){

b();

}

function b(){

alert(this);//被别的函数调用不改变上下文环境,仍然指向window。

}

a();


体现函数互调用关系的是caller:

function a(){

b();

}

function b(){

alert(b.caller);

}

a();


通过this可以很好的观察某个对象(函数)的上下文环境,在传统语言里this不难理解,指的是对象本身。在JavaScript中,函数也是个对象。如果此函数是个独立执行的函数,那么this就意味着最外层的上下文环境,也即window;如果函数定义为某个对象的属性,那么它的上下文环境就指向了这个对象。

示例:

function a(){

alert(this.name);

}

var obj1={

name:"I am obj1",

method:a  //属性是一个函数

}

obj1.method();  //函数对象的上下文是obj1


此外使用关键字call、apply可以显式改变函数的上下文环境

例如:

function a(){

alert(this.name);

}

var obj1={

name:"I am obj1",

}

a.call(obj1);  //函数的上下文是obj1


3.函数对象的定义和调用

这个本来不值一提,定义是定义,调用是调用————调用是加"()"。但是我经常看走眼,年纪大了老眼昏花。但也确实有不太好分辨的时候。比如这样:

var foo=function outer(){

return function inner(){

alert(this);

};

}();

foo();

这个例子中,foo是outer的执行结果。outer的执行结果返回的还是一个函数,所以foo也还是一个函数(其实就是inner啦,但此时并没有执行inner)。那么再执行foo的时候,上下文其实是window,自然也返回window。


4.匿名函数

匿名函数因为没有被哪个变量“记住”,所以只能定义完立即执行,通常执行的上下文是window。

比如这样:

(function(){

alert(this);

})()

更复杂一点的:

(function outter(){

return function inner(){

alert(this);

};

})()();  //此处和3小节的代码效果是一模一样的


5.闭包指的是有权访问另一个函数作用域中的变量的函数。很多开发人员混淆闭包和匿名函数——书上说的。这是因为闭包时常是以匿名函数形式来实现的,但其实二者无关。匿名函数可以单独执行,如4小节示例;闭包也可以由非匿名函数实现,例如:


function fout(){

var n=123;

return function fin(){

alert(n); //123

}

}

var f=fout();

f();  //fin访问了fout中的变量,所以尽管fout已执行完毕,但局部变量n仍被保留,从而形成闭包。


当然改成匿名函数也并非难事:

function fout(){

var n=123;

return function(){

alert(n); //123

}

}

var f=fout();

f();


总之,JavaScript是一门很有特色的语言。参考我的另一篇《JavaScript特点》


本文出自 “空空如也” 博客,请务必保留此出处http://6738767.blog.51cto.com/6728767/1586101

JavaScript作用域、上下文环境、函数对象的定义与调用、匿名函数的定义与调用、闭包