阮一峰老师微博上的关于js做用域的一道题

在阮一峰老师的微博上看到这样一道题javascript

javascriptfunction a(x, y) {
    y = function(){
        x = 2;
    };
    return function() {
        var x = 3;
        y();
        console.log(x);
    }.apply(this, arguments);
}

a();

问:输出是多少?为何?java

我想到了答案,而且验证正确,小兴奋,在这里写下解题思路:node

  • 这道题的迷惑不少
  • return其实没用,代码能够变成
javascriptfunction a(x, y) {
    y = function(){
        x = 2;
    };
    (function() {
        var x = 3;
        y();
        console.log(x);
    }).apply(this, arguments);
}

a();
  • 执行a();实际上是执行
javascriptfunction() {
    var x = 3;
    y();
    console.log(x);
}apply(this, arguments);

其中:1. this是跟做用域(浏览器环境下是window,node环境下是global),由于是在跟做用域下执行的a();。 2. arguments是空,由于a();没有参数。编程

  • y();没用。由于y定由于函数首先定义了var x = 3;,因此console.log(x)就是3。由于做用域优先级是从内向外由高到低的,因此在这里var x = 3;的优先级是最高的,y();中无论定义的什么,都不会影响到x。因此以前分析了那么多,其实都没用啊!作题时读代码,顺序要从内部到外部(仅限于作题)~

问题:这道题若是将输出改为console.log(this.x),答案会是什么? 我认为是2,但是结果确实undefined,这是为何呢? 目前我还没搞明白,求解。浏览器

javascriptfunction a(x, y) {
    y = function(){
        x = 2;
    };
    return function() {
        var x = 3;
        y();
        console.log(this.x);
    }.apply(this, arguments);
}

a();

补充

我弄明白了上面的问题,重点在于:1. 函数y的做用域,2. 函数a中定义的变量app

以前我说y();没用,为何没用?是由于函数y是定义在函数a下的,因此y的做用域链是这样的:函数

windowthis

acode

yip

由于函数a是这样定义的:function a(x, y),因此函数a定义了变量x,因此y中的x = 2;赋值给了函数ax参数。并无赋值给window做用域下的xconsole.log(this.x);this指的是window,因此输出为undefined。

若是将函数a的参数去掉,题目变成:

javascriptfunction a() {
    y = function(){
        x = 2;
    };
    return function() {
        var x = 3;
        y();
        console.log(this.x);
    }.apply(this, arguments);
}

a();

这样函数a中就没有x这个变量了,因此函数y中的x = 2;就会赋值给跟做用域下的x,因此console.log(this.x);的输出就会变成2

再将题目改一下,若是将函数y()定义在return 的匿名函数里面,题目变为:

javascriptfunction a(x, y) {
    return function() {
        y = function(){
            x = 2;
        };
        var x = 3;
        y();
        console.log(x);
    }.apply(this, arguments);
}

a();

console.log(x)会输出什么? 答案是2,由于此时y的做用域链是这样的:

window

a

匿名函数

y

由于匿名函数中定义了var x = 3;,因此函数y中的x = 2;就会修改匿名函数中的x的值,因此console.log(x)输出变成了3,


弄明白这道题的每一处细节,对理解javascript语言的做用域颇有帮助。虽然这道题对编程自己没有什么意义。

相关文章
相关标签/搜索