Javascript中的内部函数范围

时间:2015-03-23 17:44:48

标签: javascript closures

THIS文章中,我不理解以下陈述:

  

请注意,内部函数不能调用外部函数   但是,参数对象,即使它可以调用外部   函数的参数直接。

有人可以帮助我理解提到的两点

  1. 内部函数不能调用外部函数的参数对象
  2. 内部函数可以直接调用外部函数的参数。

3 个答案:

答案 0 :(得分:7)

理解这两个陈述的关键是:

  1. 了解arguments是什么

  2. 了解“影子”

  3. 那么让我们谈谈arguments,然后谈谈阴影,然后我认为这两个陈述试图说的是相当清楚的。

    arguments

    arguments对象作为函数范围的一部分提供:它实际上是一个自动定义的变量,它具有调用函数的参数的伪数组:

    function foo() {
        console.log("My arg count: " + arguments.length);
    }
    foo(1, 2, 3); // My arg count: 3
    

    当我说自动定义时,我的意思是,就像你有这个:

    // CONCEPTUAL, not real
    function foo() {
        var arguments = /*...magic code to get the arguments we were called with */;
        console.log("My arg count: " + arguments.length);
    }
    foo(1, 2, 3); // My arg count: 3
    

    ...这只是JavaScript引擎为你做的。

    arguments对象很像一个数组 - 如上所述,它有length,您可以使用通常的[]表示法访问各个参数:

    function foo() {
        var n;
        console.log("My arg count: " + arguments.length);
        for (n = 0; n < arguments.length; ++n) {
            console.log(arguments[n]);
        }
    }
    foo(1, 2, 3);
    

    输出:

    My arg count: 3
    1
    2
    3
    

    您甚至可以在同一个函数中使用命名参数和arguments伪数组:

    function foo(a) {
        console.log("a = " + a);
        console.log("arguments[0] = " + arguments[0]);
    }
    foo("Hi there");
    

    输出:

    a = Hi there
    arguments[0] = Hi there
    

    这是一个伪数组,因为虽然它有length[]索引,但它的不是实际上是一个数组,并不是全部正常数组具有的功能(如sliceforEach等)。

    在松散模式下,它还具有非常令人惊讶的属性,它链接到命名参数,所以你得到这样奇怪的东西:

    function foo(a) {
        console.log("before: a = " + a);
        arguments[0] = a * 2;
        console.log("after:  a = " + a);
    }
    foo(10);
    

    输出:

    befer: a = 10
    after: a = 20
    
    幽灵,嗯?在严格模式下,该链接不存在(因为引擎执行此操作的成本很高)。

    好的,那就是arguments。什么是“阴影”的事情?

    如影随形

    函数为变量创建“范围”,并且存在于其中,因为您可以在其他函数中包含函数,所以可以在范围内包含范围。其他函数内的函数可以访问包含它们的作用域,因此:

    function outer() {
        var a = 10;
    
        // `a` exists here
    
        function inner() {
            var b = 20;
    
            // both `a` and `b` exist here
    
            console.log("a = " + a + ", b = " + b);
        }
    
        // only `a` exists here
    
        inner();
    }
    

    a存在于outer范围内,inner可以访问。 b仅存在于inner

    只要我们使用不同的名称,那就没关系,但假设我们使用了a

    function outer() {
        var a = 10;
    
        // `a` exists here
    
        function inner() {
            var a = 20;
    
            // `a` exists here -- but which one is it?
    
            console.log("a = " + a);
        }
    
        inner();
    }
    

    由于inner有自己的a变量,因此无法再访问outer的{​​{1}} - a {{1} 阴影(隐藏)inner的{​​{1}}。

    对于变量,命名参数,在范围内创建的函数,以及在范围内赋予名称含义的任何内容都是如此。

    那么阴影与这两个陈述有什么关系呢?我们来看看......

    “1。内部函数无法调用外部函数的参数对象”

    “呼叫”在这里是错误的词; “访问”会更有意义。

    请记住上面的概念示例,其中a基本上是一个自动声明的变量?

    outer

    现在您已了解阴影,您可能会看到它的发展方向。这段代码:

    a

    显示

    Outer arg count: 3
    Inner arg count: 0
    

    ...因为在arguments内,// CONCEPTUAL, not real function foo() { var arguments = /*...magic code to get the arguments we were called with */; console.log("My arg count: " + arguments.length); } foo(1, 2, 3); // My arg count: 3 指的是内部函数的function outer() { function inner() { console.log("Inner arg count: " + arguments.length); } console.log("Outer arg count: " + arguments.length); inner(); } outer(1, 2, 3); 对象,而不是外部函数。这就像他们都声明了一个同名的局部变量:inner 阴影中的变量(隐藏)arguments中的变量。

    现在,“内部函数无法调用外部函数的参数对象”并非如此。内部函数可以访问外部函数的arguments对象,但不能访问该名称 - 如果inner将其分配给变量,则没有问题:

    outer

    显示

    Outer arg count: 3
    Outer's arg count from inner: 3
    

    “2。内部函数可以直接调用外部函数的参数。”

    此声明不完整:arguments可以访问outer的参数提供function outer() { var outerArgs = arguments; function inner() { console.log("Outer's arg count from inner: " + outerArgs.length); } console.log("Outer arg count: " + arguments.length); inner(); } outer(1, 2, 3); 不会影响他们。所以这很好:

    inner

    输出:

    Outer's a = 10
    

    ...但是在这里,outer被遮蔽,因此inner只能看到自己的function outer(a) { function inner() { console.log("Outer's a = " + a); } inner(); } outer(10); ,而不是a

    inner

    输出:

    a = undefined
    

    所以,两个陈述都是关于范围和阴影的。

答案 1 :(得分:3)

在每个函数的主体中,有一个特殊的类数组对象,名为arguments,它包含调用函数的所有实际参数。例如:

function f() {
    console.log(arguments);
}

f('one', 2, 3.0);

大多数语言都要求您声明这些参数,但JavaScript并不关心您使用的参数数量。

由于在任何给定时间(最多)范围内只有一个arguments变量,因此您无法从封闭函数访问arguments变量:

function f() {
    function g() {
        console.log(arguments);  // will log ['blue'], not ['red']
    }
    g('blue');
}

f('red');

答案 2 :(得分:1)

  
      
  1. 内部函数不能调用外部函数的参数对象
  2.   

如果你有

function outer(){
    function inner(){
       doSomething(arguments);
    }
 }

然后arguments引用直接包含该行的函数的参数。所以inner的论点。你无法从那里得到outer的论据。

  
      
  1. 内部函数可以直接调用外部函数的参数。
  2.   
function outer(a,b,c){
    function inner(d,e,f){
       doSomething(a,b,c);
    }
 }

只要保持参数(和局部变量)名称不同,您仍然可以从outer内部访问inner的参数(这里是a,{{ 1}}和b)。