一道《有意思的题目》

偶然看到老陈有意思的题目,果然有意思!在这里拿来分析分析,原题如下:

<script type="text/javascript">
    function test(num) {
        this.m_num = 5;
        
        var func1 = function() {
            alert(num);
            alert(this.m_num);
        }
        
        this.func2 = function() {
            func1();
        }
        
        this.func3 = func1;
    }
    
    new test(1).func2();
    new test(1).func3();
</script>

运行结果:

1

undefined

1

5

 

这道题考了至少三个知识点:

1、函数的执行环境

2、this 绑定

3、匿名函数的特殊性

 

     首先,每个函数在执行时都会创建一个属于自己的执行环境。每个执行环境都对应一个对象,这个对象包含了在当前执行环境中定义的所有变量和函数。在 Javascript 中,是没有面向对象语言中所谓的块作用域的,变量的作用域就是通过它所在函数的执行环境限定的。换句话说,是借助于执行环境的关联对象来实现的。当一个函数在另一个函数内部执行时,它的执行环境会嵌套在包含它的函数的执行环境中。此时,内部环境可以访问外部环境中的变量,但反过来则是不允许的。当有两个及以上函数嵌套时,这些函数的执行环境组成了一个作用域链。在解析一个变量时,解析器首先会去当前执行环境中查找是否有其定义,如有则停止查找并返回值;否则会沿着作用域链向上一层执行环境中查找,如发现定义则停止查找立即返回;如还未找到,解析器会再次沿着作用域链向更外一层执行环境中查找,直至找到为止;如遍历完最外层作用域之后仍未找到,此时解析器就会把它当成一个尚未定义的变量处理。在 Web 浏览器中,任何时候,尚未定义的变量都会被当作全局作用域中的变量,全局作用域即 window 域。同时,任何自定义函数的最外层执行环境的始终是全局执行环境。

 

     任何函数都具有两个对象:this 和 arguments。在函数内部,可以通过 this 来访问其作用域中的变量。但 this 并不是指与函数执行环境关联的对象,而是指调用函数的对象。在浏览器中,任何函数都是作为某个对象的方法来调用的。我们可以通过函数的两个固有方法 apply() 和 call() 来指定函数的调用者,同时也改变了其执行环境。用法如下:

function showName(){
    alert(this.name);
}

var jeneral1 = {name:'zhangfei'};
var jeneral2 = {name:'zhaoyun'};

showName.apply(jeneral1);
showName.apply(jeneral2);

所以,this 所指的对象并不能在函数声明时确定,而是和其具体的执行环境密切相关,是一个运行时的概念。

 

     在函数表达式中,我们常用匿名函数作右值:

var init = function(){

        …

};

     匿名函数特殊的地方在于其 this 绑定于 window 对象,但仍然遵守作用域链的规则。匿名函数常用来模仿块级作用域,如下形式:

(function(args){

     …

})(args)

    

 

好,有了上面的了解之后再回来看题。首先,原题可以写成如下的等价形式:

<script type="text/javascript">
    function test(num) {
        this.m_num = 5;
        
        this.func2 = function() {
            (function() {
                alert(num);
                alert(this.m_num);
            })();
        }
        
        this.func3 = function() {
            alert(num);
            alert(this.m_num);
        };
    }
    
    new test(1).func2();
    new test(1).func3();
</script>

这下就直观多了!执行函数 func2() 的时候,由于函数体包含的是一个匿名函数,它可以访问外部环境中的对象变量,故为 1 。然而它的 this 却指向 window 对象,全局作用域中没有定义 m_num ,所以是 undefined。执行 func3() 时,由于它是调用对象的方法,因此 this 指向这个对象,故为 5。

 

     完毕。

posted @ 2011-04-09 12:42  ihada  阅读(440)  评论(3编辑  收藏  举报