js 函数作用域问题

function shit(){
    console.log(a)
}

function fuck(callback) {
    var a = 'shit';
    callback()  //error: 'a' undefined
}


fuck(shit)
  

为什么callback不能找到变量a?
下面就可以

function shit(){
    console.log(a)
}

function fuck(callback) {
    var a = 'shit';
    function hey() {
        console.log(a)
    }
    hey()
}


fuck(shit)
阅读 3.5k
5 个回答

JS里变量的查找,是按照函数定义的位置,而不是调用的位置确定的。

比较简明的说是:
第一个是函数调用。fuck只是调用了shitshit的定义不在fuck中而是在全局,所以shit的外层并不是fuck,它的外层是全局。
第二个hey的的定义在fuck中,所以其外层就是fuck,故当hey中没有定义这个变量时候就会查找fuck生成的作用域。如果fuck中还没有就继续查找fuck的外层,也就是全局。

详细的参考:http://zonxin.github.io/post/...

与函数的执行环境有关,看似 shit 是在 fuck 中执行的,实际上,它真正的执行环境是 window. 所以作用域链中是无法找到a的。

下面是一个验证:

    var a = "window a";
    function shit() {
        console.log(a)
    }
    function fuck(callback) {
        var a = 'shit';
        callback()  //window a
    }
    fuck(shit)

function shit(a) { console.log(a) }
function fuck(callback) { var a = 'shit'; callback(a) }
fuck(shit)

作用域链= AO + 函数内部[[Scope]]属性(不够准确,但一般其他的用不着,如with,eval什么的,let和const,这2个须注意下,也比较简单),
1AO:函数被调用时的变量对象。其中包括此函数内部的变量名,函数到声明,参数(这些能访问)
2函数内部的[[Scope]]:简单来讲就是,此函数可以访问它父级(它爸爸的爸爸----直到全局)的变量名,函数的声明,参数(如果父级是一个函数)。其中特别重要特性的是静态,当然有特殊的,不过一般用不着就不说。即该函数创建的位置,不是调用的位置。
3shift创建在全局,所以只能访问全局的变量a,不是在调用处的a,
4AO的优先级最高,其次是它爸爸--它爸爸的爸爸------直到全局
5第2种,函数创建在函数内部,当然能调用
6拓展下:如果你对scope 了解清晰了,闭包可以说就没什么问题了,注意一个共享特性如下
var inner1,inner2;
function fn(){

var a = 1;
inner1 = function(){console.log(++a)};
inner2 = function(){console.log(--a)};

};
fn();
inner1();//2
inner2();//1
inner1和inner2在同一个函数内,所以内部[[Scope]]中保存的a是一样的

1、第一个函数function shit(){ console.log(a)}里的变量a没有定义,全局变量里也没有这个变量,所以只要运行第一个函数必定会提示a is not defined .
2、第二个函数function fuck(callback) { var a = 'shit'; callback()}定义a变量,但它只是这个函数的局部变量,并不会影响到外面的其他函数,其实这里定义不定义a这个变量一点影响都没有。第二个函数在这里的真正的作用是让传入的函数参数成为一个函数并且运行它。所以运行第二个函数,并且用第一个函数做为参数传进去,相当于去调用运行了第一个函数。所以就提示a is not defined 。
上面1,2,两条是讨论为什么你列的第一种情况说为什么找不到变量a,下面就来说一下你列出的第二种情况。
3、第一个函数情况和上面第一种情况一模一样。
4、第二个函数同样传了一个叫callback的参数,但其实传这个参数对运行这个函数一点影响都没有,这个函数运行后的值已经固定死了,值就是shit,你传什么参数,第二个函数的运行后的值都是shit。

现在总结一个为什么你会觉得有问题,因为第一种情况,函数有运行了第一个函数,而运行第一个函数都会提示找不到变量a,而第二种情况,第二个函数根本没和第一个函数任何瓜葛,不像第一种情况的第二个函数有去调用运行它。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题