js匿名函数声明时的作用域

最近看了一些解释js词法作用域的文章,于是有一个问题

//静态作用域测试  1
var finn = function() {
    var x = {
        a: "a",
        b: "b"
    };
    queen(function() {
              x.a = "c";
              console.log(x.a);
    })
};
var queen = function(callback) {
    callback()
};
finn();
//静态作用域测试  2  
var finn = function() {
    var x = {
        a: "a",
        b: "b"
    };
    queen()
};
var queen = function() {
    x.a = "c";
    console.log(x.a);
};
finn();

这里测试一的结果是打出“c”,测试二的结果是x undefined,用静态作用域来解释是可以行的通的,函数的作用域在被定义时已经确定,所以1有值,2无值。 这里想要问的是对于测试1中,

queen(function(){
     x.a="c";
     console.log(x.a);
})    

是否等价于

var qop = function(){
    x.a="c";
     console.log(x.a);
};
queen(qop);

下面这种方式可以比较直观的看出,该匿名函数的声明位置在finn内部,所以它的作用域链上有finn的变量作用域

阅读 3.8k
4 个回答

对于函数表达式的情况,你完全可以把这个函数当成一个值,所以

doSomething(1);

var a = 1;
doSometing(a);

基本等价,同理

doSomething(function() {});

var f = function() {};
doSomething(f);

也就是基本等价。

为什么说是基本等价……因为有一个变量定义的区别。

对于作用域的理解,以 C 语系的语言中,基本上都可以用 {} 的范围来理解,只不过 C/C++ 中存在局部变量即时销毁的问题,而 JavaScript 的 var 变量作用域不是按块范围,而是按 function() {} 范围的。ES6 的 let 变量就是块范围了。

所以,要看一个函数有没有权限访问一个 var 变量,只需要看访问这个 var 变量的语句是不是在定义 var 变量的那个 function 的大括号内部即可。

我们只需要说x这个对象的作用域就可以了,函数A内变量的作用域是可以延伸到函数的子函数内的,但是子函数需要在函数A里面定义,这是不是解释了测试2为什么访问不到x了?对于一,你用x只是作为queen的参数,有什么理由访问不到呢?

依照题主结尾的疑问
片段1

var finn = function(){
    var x={
         a:"a",
         b:"b"
     };
      queen(function(){
          x.a="c";
          console.log(x.a);
      })    
};
 var queen = function(callback){
     callback()
 };
 finn();

片段2

var finn = function(){
    var x={
         a:"a",
         b:"b"
     };
     var qop = function(){
          x.a="c";
          console.log(x.a);
    };
    queen(qop);  
};
 var queen = function(callback){
     callback()
 };
 finn();

这两个片段是等价的。内部函数所能访问的外部作用域,确实取决与它在定义时的位置(或者说,函数体的位置),而该内部函数的内部定义的变量,也只能在该内部函数及该内部函数的内部函数可访问。

哇,说到作用域居然没提到this,感觉有点幸福。。。

首先作用域,就是js搞事的地方,一般来说那些概念性的东西我记不来,我主要记住是下面这种形式:

    function(){
        /*作用域A*/
        function b(){
            /*作用域B*/
        }
        function c(){
            /*作用域C*/
        }
    }
  • 就像正则匹配一样,见到形如function开头存在{}的语句,大括号里面就是一个作用域。(有关于json对象的内部是否属于作用域,这个我也是有点疑惑的,望有大神解答

  • 正如上面的代码,子作用域可以访问父作用域的变量和函数,但是父作用域不能访问子作用域的变量和函数。然后是作用域B和作用域C不能相互访问。。。你可以这样理解:作用域是函数的老婆,儿子可以亲妈妈对吧,但是父亲不能亲儿媳妇,弟弟也不能亲嫂子,这样家庭就会出问题(我他妈都在说什么。。。)

  • 那好,回到你的代码,首先是测试1,我们看看作用域的结构是怎么样的:

    var finn = function() {
        /*作用域a*/
        var x = {
            a: "a",
            b: "b"
        };
        queen(function() {
            /*作用域b*/
            x.a = "c";
            console.log(x.a);
        })
    };
    var queen = function(callback) {
        /*作用域c*/
        callback()
    };
    finn();
    
    /*很明显啊,作用域b可以访问到作用域a里面的东西啊,因为作用域b是作用域a的子域*/
    /*callback()只是负责执行,没有负责定义函数和生成作用域啊。。。*/

然后是测试2的:

    var finn = function() {
        /*作用域a*/
        var x = {
            a: "a",
            b: "b"
        };
        queen()
    };
    var queen = function() {
        /*作用域c*/
        x.a = "c";
        console.log(x.a);
    };
    finn();
    
    /*很明显,queen想亲他嫂子,这怎么可以!所以js给了他一巴掌:undefined*/
    /*作用域a和作用域c没有关系,作用域c无法访问作用域a里面的内容,反之亦然*/
    
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题