4

因此,通过以下代码,我向自己证明了嵌套函数确实获得了外部函数参数的副本:

    var o = {};
    (function(a,b,c,x){
        x.f = function(){
            return a.toString()+b.toString()+c.toString();
        }
    })(7,4,2,o);
    o.f();

代码产生

    742

这意味着该o.f函数从匿名函数中获得 a、b 和 c 的副本。否则,我只会得到undefinedundefinedundefined

我的问题是,

  • 首先,这总是正确的吗?还是有严格的条件?(比如,它必须是一个对象吗?等等)
  • 此外,在 javascript 中还存在哪些其他类型的模糊范围?我很想知道(即第三次迭代呢?)
  • 最后,我可以阅读一份解释 javascript 范围的高级概念的文档。有谁知道有什么好的吗?
4

4 回答 4

11

您观察到的称为词法范围。这意味着JavaScript中某个范围内的变量的绑定是由变量在代码中出现的位置决定的。它总是正确的,在任何层面上都是正确的。唯一的主要例外是this值,它是动态作用域而不是词法作用域。动态范围意味着函数中的变量取决于调用函数的方式和时间。(请参阅词汇范围和动态范围。)

例子:

var o = { 
    a: function() {
        var x = 5;
        console.log(this, x);
        function b() {
            console.log(this, x);
        }
        b();
    }
};

o.a();

此示例的结果将是:

{Object o} 5
{window} 5

换句话说,第一个console.log将记录this为对o对象的引用,而第二个console.log将记录this为对window对象的引用。但是,两者都将记录x为等于5。的值thiswindow在没有上下文的非严格模式下调用它时。所以this不是词法范围的,而是其他变量,比如x。要了解有关行为的更多信息,this请参阅A Short Overview ofthis .


直接回答您的问题:

1. 首先,这总是正确的吗?还是有严格的条件?(比如,它必须是一个对象吗?等等)

this是的,这是真的,除了arguments基于函数调用方式的变化。它不必是一个对象,所有变量都是词法范围的。


2. 另外,javascript 中还有哪些类似这样的晦涩作用域?我很想知道(即第三次迭代呢?)

您可以随心所欲地深入——内部函数始终可以访问其外部函数的变量。

function a() {
    var x = 1;
    console.log('a:', x);
    return function b() {
        var y = 2;
        console.log('b:', x, y);
        return function c() {
            console.log('c:', x, y);
        };
    };
}

var foo = a();   // => logs 'a: 1'
var bar = foo(); // => logs 'b: 1 2'
bar();           // => logs 'c: 1 2'

这实际上是另一个称为闭包的主题的一部分,当您从另一个函数中返回一个函数时会发生这种情况。


3. 最后,我可以阅读一份解释 javascript 范围的高级概念的文档。有谁知道有什么好的吗?

我已经链接到几个资源。另一个不错的:

MDN:函数和函数范围(特别是关于嵌套函数和闭包的部分)。

此外,阅读有关闭包的任何内容都会使您受益,并且您可能还想查找词法范围

于 2012-12-09T06:13:54.770 回答
1

您需要做的就是阅读闭包。http://en.wikipedia.org/wiki/Closure_(computer_science ) 内部函数没有获得该变量的副本,而是获得对该变量的引用。例子:

var o = {};
(function(a,b,c,x){
    x.f = function(){
        return a.toString()+b.toString()+c.toString();
    }
    a++;
})(7,4,2,o);
o.f();

产量

842

编辑:好的,也许这不是您需要阅读的全部内容。我只是认为值得证明这个概念对许多语言来说并不陌生。

于 2012-12-09T05:57:08.740 回答
1

我在代码中使用这个概念时犯了一个愚蠢的错误,并错误地将参数重新声明为变量。在这里发帖以防它帮助别人。

(function(){
var outerFunction=function(varA){
    console.debug('value of varA in outer function '+varA);
    var innerFunction = function(){
        console.debug('value of varA in inner function '+varA);
    }
    innerFunction();
};
outerFunction("hi");

var buggyOuterFunction=function(varA){
    console.debug('value of varA in buggy outer function '+varA);
    var buggyInnerFunction = function(){
        var varA = varA || "hello"; //BUG - do not redeclare
        console.debug('value of varA in buggy inner function '+varA);
    }
    buggyInnerFunction();
};
buggyOuterFunction("hi");
})();

输出:

value of varA in outer function hi
value of varA in inner function hi
value of varA in buggy outer function hi 
value of varA in buggy inner function hello
于 2013-09-10T06:54:09.540 回答
0
  • 是的,这适用于所有类型。javascript 设计的这个元素称为“闭包”。在谷歌搜索其他阅读材料时使用它。
  • 创建函数的嵌套深度没有语言限制,只有可维护性限制。通常在第 2 级之后,您会进入“封闭地狱”或“封闭意大利面”,是时候重构了。因此,您可以将函数嵌套 4 层,并从函数 4 中的代码访问函数 1 的参数。
    • 我想到了另外 2 个“晦涩难懂”的案例:
      • 如果您直接调用一个函数而没有显式this绑定,this则绑定到全局(窗口)对象。这被普遍认为是 javascript 中的严重缺陷之一。谨防。
      • JavaScript 具有“函数提升”,这意味着即使实际的函数定义在同一范围内的源代码文件中进一步向下,也可以从范围的顶部引用函数。
  • 只需阅读 Douglas Crockford 的JavaScript: The Good Parts 即可。还有许多很棒的教程和在线书籍免费提供,并且可以通过网络搜索轻松找到。只要确保它们是现代的(大部分时间不早于 2010 年编写)。
于 2012-12-09T06:01:20.090 回答