【问题标题】:Calling a function before it is declared, browser independent?在声明之前调用函数,独立于浏览器?
【发布时间】:2012-06-07 03:07:35
【问题描述】:

如果我在我的<head> 标签中这样做:

<script type="text/javascript" src="foo.js"></script>

在 foo.js 中我这样做:

var foo = new Foo();
function Foo()
{
   //code here
}

即使变量 foo 包含在函数定义的上方,这段代码是否会可靠地实例化变量,或者我应该将其移动到文件的底部,如下所示:

function Foo()
{
   //code here
}
var foo = new Foo();

【问题讨论】:

标签: javascript


【解决方案1】:

您的示例可以在任何遵循 ECMAScript 标准的浏览器中运行(至少在这个问题上都可以)。

请参阅specification 的第 10.3-10.5 节。

首先设置本地范围,然后实际运行函数体。

阅读 10.5(该部分确实不是很长)以了解为什么 @meder 的答案是正确的。

如果您不想自己阅读规范:

10.5 告诉以该顺序声明变量(如果某个名称出现两次则覆盖):

从外部范围继承=设置会影响外部范围:

  • 周围范围的变量。
  • 自己的函数名。

本地范围 = 设置不会影响外部范围:

  • 参数(从左到右)。
  • 参数对象。
  • 声明所有内部变量(如果有则不覆盖当前值,undefined 如果还没有)

总而言之:

返回函数 x 本身:

function x() {
    return x;
}

返回参数x:

function x(x) {
    return x;
}

返回内部函数x:

function x(x) {
    return x; // the return does no harm, x is already set
    function x() {} // before the actual body is evaluated
}

也返回内部函数x:

function x(x) {
    var x; // in this case a no-op 
    return x;
    function x() {}
}

返回 42:

function x(x) {
    var x = 42; // overwrite x in local scope
    return x;
    function x() {}
}

返回第二个参数:

function x(x,x) { // assign left to right, last one "wins"
    return x; // arguments[0] would still name the first argument
}

第二次调用x 时返回 2,因为 x 设置为内部函数:

function x() {
    x = function() { return 2; } // set x in outer scope
    return 1;
}

【讨论】:

  • +1 表示不使用“提升”,但注意相关部分是进入global context,而不是函数上下文,这主要影响this的值。
  • 我不明白该规范如何回答我的问题?可以翻译成英文吗?
  • 简单来说,对于全局代码,this 设置为全局对象,然后处理函数声明,然后是变量声明,然后是可执行语句。进入每个函数时,都会发生类似的过程,但设置this的值和范围更复杂。
  • @RobG 是的,我故意忽略了this。 :)
【解决方案2】:

只有通过var定义才需要移到上面,如:

var Foo = function(){};
var foo = new Foo;

否则,据我所知,解释器会提前读取函数定义。

【讨论】:

    【解决方案3】:

    据我所知,JS 对你的代码这样做是因为提升:

    var foo;          //var declarations hoisted up
    function Foo(){   //function declarations hoisted up
       //code here
    }
    foo = new Foo();  //the operation
    

    所以应该没问题。但是,我不会仅仅依靠提升,因为至少对我来说,当声明到处都是时很难调试。为便于阅读,请按以下顺序排列代码:

    • 变量声明
    • 功能
    • 操作

    code 1:

    console.log(foo); //undefined
    var foo = new Foo();
    console.log(foo); //Foo
    function Foo(){
       //code here
    }
    console.log(foo); //Foo
    
    //acts like:
    var foo;          //var declaration hoisted up
    function Foo(){}  //function declaration hoisted up
    console.log(foo); //undefined
    foo = new Foo();
    console.log(foo); //Foo
    console.log(foo); //Foo
    

    code 2:

    console.log(foo); //undefined
    function Foo(){
       //code here
    }
    console.log(foo); //undefined
    var foo = new Foo();
    console.log(foo); //Foo
    
    //acts like:
    var foo;          //var declaration hoisted up
    function Foo(){}  //function declaration hoisted up
    console.log(foo); //undefined
    console.log(foo); //undefined
    foo = new Foo();
    console.log(foo); //Foo
    

    【讨论】:

    • 我认为他是在询问第一个示例中的 Foo 函数声明而不是 foo 变量声明,因为在该示例中,函数在其声明出现之前被调用。
    • @amnotiam 是的,这个变量可以命名任何东西,我想知道如果放在 Foo() 函数的定义之上,它是否会被可靠地实例化
    • 它也将函数语句提升为var Foo = function Foo () { // ... };
    • @ClickUpvote:通过 instantiated,您是在询问 new Foo() 是否会工作,因为它相对于 function Foo() {...} 的声明发生“无序”,正确的? ...无论如何,答案是肯定的。函数声明发生在封闭范围内的任何代码执行之前。
    • 我认为@Peter 使用变量赋值语法来说明该函数将可用,就好像该代码位于函数的顶部一样。他用那个语法来说明它只是有点令人困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    • 2018-12-29
    相关资源
    最近更新 更多