javascript变量预解析与函数声明提前

这里同时出现了函数声明提前,和变量的预解析,但是不管var foo = 11;放哪里,都返回function(这里表述有误为什么SF中Markdown的~~删除线~~不能用...),是什么原因

    function bar() {
        return foo;
        foo = 10;
        function foo() {};
        var foo = 11;
    }
    console.log(typeof bar());//function 为什么不是number

网上查的资料:

http://www.bootcss.com/article/variable-and-function-hoisting-in-javascript/
解析器将当前作用域内声明的所有变量和函数都会放到作用域的开始处
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
function:Three forms with different scope behavior:
(为什么有三种...)
declared: as a statement at the parent function top-level
behaves like a var binding that gets initialized to that function initialization
**"hoists" to the very top of the parent function, above vars**
函数声明提前到当前作用域最顶端,在var之上,但还是不懂:最顶端,那不会被后来的var给覆盖么
statement:as a statement in a child block
behaves like a var binding that gets initialized to that function
does not hoist to the top of the parent function
expressed: inside an expression bound in the expression only

然后现在,问题变成了:为什么var foo无论放在function foo...前面还是后面,都返回function

function bar() {
    var foo;
    function foo() {};
    return foo;
}
console.log(typeof bar());
阅读 11.8k
6 个回答

答案如 @yofine 代码所写,var foo = 11实际上是两句话var foo; foo = 11,函数中只有声明(包括变量声明和函数声明)会被提前(hosited),所以foo = 11还是原来的位置。两次赋值都在return 之后所以自然是Function了,如果把foo = 10放到return 前面就是Number了。


新问题参见这里(引自:http://www.cnblogs.com/MockingBirdHome/p/3385152.html):

如果存在函数声明和变量声明(注意:仅仅是声明,还没有被赋值),而且变量名跟函数名是相同的,那么,它们都会被提示到外部作用域的开头,但是,函数的优先级更高,所以变量的值会被函数覆盖掉。

// Both the variable and the function are named myName
var myName;

function myName () {
console.log ("Rich");
}

// The function declaration overrides the variable name
console.log(typeof myName); // function

但是,如果这个变量或者函数其中是赋值了的,那么另外一个将无法覆盖它:

// But in this example, the variable assignment overrides the function declaration
var myName = "Richard"; // This is the variable assignment (initialization) that overrides the function declaration.

function myName () {
console.log ("Rich");
}

console.log(typeof myName); // string

另外,~~做删除线的是Markdown的扩展语法,SF对扩展语法支持的不全,你可以直接使用HTML标签做删除线

由于js有声明提前,你的代码等同于下面。

  function bar() {
        var foo;
        function foo() {};
        return foo;
        //以下不会被执行
        foo = 10;        
        foo = 11;
    }
    console.log(typeof bar());
function bar() {
  var foo;
  return foo;
  function foo() {};
  foo = 11;
}

function foo() {}
函数声明会在执行前被解析 存在于当前上下文的任意一个地方 typeof(foo) 已经为 Function
var foo = 11 只会提前声明出变量 foo

函数声明会在任何表达式被解析和求值之前先被解析和求值,即使你的声明在代码的最后一行,它也会在同作用域内第一个表达式之前被解析/求值

因为你这种情况出现时, 都已function为准, 不管顺序如何.

在ECMAScript中,有一个叫做执行上下文(Execution Contexts)的概念,他在理论上规定了函数在执行时的执行顺序[具体则是由浏览器引擎来实现,不过chrome的v8引擎和firefox的 xxx-spider引擎在实现上会有一些细节的差异。],这里涉及到的2个执行顺序的规则如下:

  1. 使用function声明的函数会最先被编译,因此在相同作用域中,我们总能直接使用function声明的函数;

  2. 使用var声明的变量和函数表达式会被自动提升到作用域的顶部,这种现象叫做hoisting

于是这个问题就很好解释了。
想要深入了解执行上下文,可点击这里
你也可以继续阅读汤姆大叔的这系列文章,非常有价值.深入理解javascript系列

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