立即执行函数与作用域问题1

题目如下:

var x = 10;

function fn(){

    console.log(x);

}

function show(f){    

    var x = 20;

    (function () {

        f();

    })();

}

show(fn);

从题目可以看出,这里在全局和函数内部声明了两个同名的x变量。函数show内部还有一个立即执行函数。其实这些都是烟雾弹,这道题其实是主要想考查,我们对于作用域链的理解,下面我们来分析下:

1.首先在全局范围内,声明了两个函数 fn,show和一个x变量,全局环境执行,导致fn的定义,定义后,函数fn的作用域链上就拿到了父环境的作用域链,简单点说,fn现在的作用域链上只有一个全局global对象,而global对象上只有两个函数,一个x变量。

2.声明阶段完成后,在全局环境下,调用了show这个函数,并且把函数fn这个函数的引用当成实参传进了show函数体内。

3.show函数体内,同样声明了一个x变量,但是这个x其实是添加到show函数的作用域上,还声明了一个立即执行函数,在立即执行函数中,执行了fn的引用。fn执行会生成自己的活动对象(Active Object),并将自己的活动对象放在作用域的第一位。这个时候fn函数的作用域链就是AO(fn)-->GO(Global Obect)。

4.函数执行时,查找作用链上是否有访问的变量,都是顺着作用域链查起,也就是说从自己的AO查起,到GO结束。当然有些特殊用法,也有意外,比如with的用法。从上面的例子可以看出,函数fn的作用域链和show的作用域链基本上没关系。所以也就访问不到show内部声明的变量x,fn打印的其实就是全局声明的x。

5.最后说明一下,这里放在立即执行函数内,只是一个烟雾弹,删掉立即执行函数也不会改变fn的作用域的,打印的结果同样是10。

var x = 10;

function fn(){

    console.log(x);

}

function show(f){

    var x = 20;

    f();

}

show(fn);

6.最后,再佐证下,fn和show的作用域没关系。这里在show内声明了一个m,如果fn和show的作用域有关系,打印m,应该可以打印出10,事实上没有找到m。

var x = 10;

function fn(){

console.log(m);

}

function show(f){

    var x = 20;

    var m = 10;

    (function () {

        f(m);

    })();

}

show(fn);

结果:


结果显示m未声明

你可能感兴趣的:(立即执行函数与作用域问题1)