声明为参数时的函数名称可见性

Function name visibility when declared as an argument

本文关键字:可见性 函数 参数 声明      更新时间:2023-09-26
function foo() {
    ui.login.setClose(function closer() {
        ui.hideAll()
        ui.main.show()
    })
    ui.ask.setClose(closer) // <-- closer is not defined
    ui.adduser.setClose(closer)
}

我想知道为什么这不起作用?function关键字不应该在当前函数 (foo) 主体中的任何位置创建一个可见的名称吗?

你那里的东西叫做命名函数表达式。(不要在IE8或更早版本或其他一些相当旧的浏览器中使用它们。它在几个方面与函数声明不同,其中之一是(在正确的实现上)函数的名称不会添加到创建它的作用域中。

在该示例中,您可能想要一个函数声明,要么在 foo 中,要么在 foo 中访问:

function foo() {
    function closer() {
        ui.hideAll()
        ui.main.show()
    }
    ui.login.setClose(closer);
    ui.ask.setClose(closer);
    ui.adduser.setClose(closer);
}

或外部foo如果您希望在foo外部访问:

function closer() {
    ui.hideAll()
    ui.main.show()
}
function foo() {
    ui.login.setClose(closer);
    ui.ask.setClose(closer);
    ui.adduser.setClose(closer);
}

以下是创建函数的三种主要方法的概要(除了 Function 构造函数,几乎总是应该避免):

函数声明

看起来像这样:

// `foo` is in scope *and* ready to use here, even before the declaration
function foo() {
    // `foo` is in scope and ready here too
}
// `foo` is in scope and ready here too

特性:

  1. 作为分步代码的一部分进行处理;而是在运行作用域中的任何分步代码之前创建。这意味着您可以在声明上方和声明下方编写的代码中使用上面的foo

  2. 由于 #1,函数声明不能在控制结构(如 ifswitchfor 等)中,因为在分步代码运行之前创建函数时,这毫无意义。(重要的是不要这样做,因为不同的浏览器以不同的方式处理无效位置。

  3. 将函数的名称放在显示函数声明的范围内。

  4. 该函数具有真实名称,并且该名称在函数范围内。

命名函数表达式

这看起来完全相同,只是它是在预期表达式的地方编写的,例如在=(例如,赋值)或:(在属性初始值设定项中)的右侧,或者作为函数的参数:

// `foo` is *not* in scope here
var x = function foo() {
    // `foo` is in scope here, refers to the function
};
var obj = {
    x: function foo() {
        // `foo` is in scope here, refers to the function
    }
};
bar(function foo() {
    // `foo` is in scope here, refers to the function
});
// `foo` is *not* in scope here

特性:

  1. 它们作为分步代码的一部分进行处理,就像任何其他表达式一样。

  2. 它们
  3. 现代浏览器(包括IE9及更高版本)上正常工作,但是IE8及更早版本中存在错误,其他一些相当旧的浏览器也有错误(kangax当时编写了它们)。

  4. 作为表达式,它们有一个结果:函数引用。(例如,这就是分配给x或传递给上面的bar的内容。

  5. 它们
  6. 的名称不会添加到定义它们的作用域中。

  7. 该函数有一个真实名称,并且该名称在函数范围内(例如,用于递归)。

匿名函数表达式:

与命名函数表达式相同,但是,呃,没有名称:

var x = function() {
    // ...
};
var obj = {
    x: function() {
        // ...
    }
};
bar(function() {
    // ...
});

特性:

  1. 它们作为分步代码的一部分进行处理,就像任何其他表达式一样。

  2. 它们会产生一个函数引用(例如,这就是分配给x或传递给上面的bar的内容)。

  3. 该函数在当前规范中没有名称。但是,下一个规范 ES6 将让引擎通过查看表达式来推断函数的名称。例如,在上面,分配给x的两个都将具有名称x ;传递给bar的那个仍然是匿名的。

您需要

将其声明为函数,而不仅仅是回调函数。

像这样:

function foo() {
    function closer() {
        ui.hideAll()
        ui.main.show()
    }
    ui.login.setClose(closer);
    ui.ask.setClose(closer) // <-- closer is not defined
    ui.adduser.setClose(closer)
}

在这种情况下

setClose()

除了函数作为参数,该参数在您的代码中仅在 () 中定义,因此它在 setclose() 之外不可用。如果参数中只需要函数,则通常使用这种定义函数的方法。这就是为什么在这种情况下,原则上不需要为其指定名称:

ui.login.setClose(function() { ui.hideAll(); ui.main.show(); });

但是,在您的情况下,您必须独立于函数 setclose() 定义函数 closer():

function closer() {
   ui.hideAll();
   ui.main.show();
}
function foo() {
   ui.login.setClose(closer);
   ui.ask.setClose(closer);
   ui.adduser.setClose(closer);
}

您还错过了一些 ; 结束这一行。