4

I was looking through the code of a JS library and saw this pattern:

function module() {
    function func() {
        //...
        definedAfter();
        //...
    }
    return func;
    var x = "....";
    function definedAfter() {
        //...
        console.log(x); //outputs undefined
        //...
    }
}

Google's Closure compiler flags the variable x as unused code, which seems reasonable, but the interesting part is that the variable is declared but with a value of undefined (due to hoisting).

Is this a bug in the library? Or is there some subtle behavior that is being exploited here? Maybe some type of optimization? Do different browsers act differently with regard to this example?

EDIT: I'm curious about the intent (bug or otherwise) of the original code, since it seems like x would always be undefined.

4

3 回答 3

3

我想你理解提升,但这里是对该函数在技术上的样子的解释:

function module() {
    function func() {
        //...
        definedAfter();
        //...
    }
    function definedAfter() {
        //...
        console.log(x); //outputs undefined
        //...
    }
    var x;
    return func;
    x = "....";
}

(我不确定被吊起的东西的实际最终顺序,但我认为这并不重要)

所以最后x = "....";一行永远不会被执行,但x仍会被声明(as undefined),并且可以被内部函数范围访问。

所以我不得不说图书馆有一个“错误”,因为设置x为“....”的行永远不会到达并且什么都不做。

于 2013-04-15T16:34:41.800 回答
1

根据 Benn Flynn 的评论,解析器在实际执行之前预扫描和/或编译代码。因此,它会检测块中任何行的变量范围,无论是否执行。

在浏览器的控制台中运行它:

var f = function() {
  // we haven't defined a local x yet, so we're tempted to think
  // that this line is mucking with window.x
  x = 1;
  console.log(x, window.x);
  return;

  // and we're tempted to think this line is never seen, because it
  // occurs after the return. but, it ensures that x is local, not global.
  var x = 2;
};
f();

在您的控制台中,您会看到如下内容:

1 undefined

之后,window.x就不存在了。由于我们的声明,它没有在任何地方被提及——声明的赋值部分是否必要,我不确定。不应该。但是,如果不存在分配,我知道某些版本的 IE 会忽略声明,我不会感到惊讶。

将其与此进行比较:

var f = function() {
  x = 1;
  console.log(x, window.x);
  return;
  x = 2;  // this line truly does nothing.
};
f();

我们在控制台中看到了这一点:

1 1

之后,windows.x1

值得注意的是,它definedAfter()可以正常工作,因为它不是以变量赋值形式编写的:

// this puts definedAfter in scope, but it's undefined unless this line is
// actually executed
var definedAfter = function() { /* whatever */ }

相反,它是以“函数声明”形式编写的,不会被“执行”。

function definedAfter() { /* whatever */ }

相反,编译器在编译期间看到它并说:“哦,这个函数是作用域的一部分。” 这种差异使您能够在变量赋值语法中精确控制您的函数何时可用。并且在函数声明形式中,能够在任何地方定义函数而无需担心执行顺序。

于 2013-04-15T16:35:03.117 回答
0

No, it's not a bug in the library. Yet, it's not the most elegant code.

There are two things you need to know to understand it better

1) The meaning of hoisting 2) the difference between Function expressions and Function declarations is subtle and yes different browsers act differently.

(for the latter see: http://kangax.github.io/nfe)

cheers

于 2013-04-15T16:38:42.663 回答