JavaScript 中的命名函数比匿名函数更受欢迎吗?

IT技术 javascript
2021-03-05 11:52:03

可能的重复:
JavaScript:var functionName = function() {} vs function functionName() {}

在 Javascript 中提取函数有两种可能的方法:

var foo = function() { ... }

这有点做作;另一种常见的模式是:

var foo = {
   baz: 43,
   doSomething: function() {
       // ...
   }
}

相对

function foo() { 
  // ... 
}

是否有明确的理由选择其中之一?

4个回答

这一切都归结为对声明函数的位置的偏好;吊装。

函数声明和变量声明总是被 JavaScript 解释器无形地移动(“提升”)到它们的包含范围的顶部。显然,函数参数和语言定义的名称已经存在。这意味着这样的代码:

function foo() {
    bar();
    var x = 1;
}

实际上是这样解释的:

function foo() {
    var x;
    bar();
    x = 1;
}

请注意,声明的赋值部分没有被提升。只挂了名字。函数声明不是这种情况,整个函数体也将被提升。

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

在这种情况下,只有函数声明的主体被提升到顶部。名称 'foo' 被提升,但主体被留下,在执行期间被分配。

您可以为函数表达式中定义的函数命名,其语法类似于函数声明。这不会使它成为函数声明,并且名称不会进入范围,也不会提升主体。

foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
bin(); // ReferenceError "bin is not defined"

var foo = function () {}; // anonymous function expression ('foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted)

foo(); // valid
bar(); // valid
baz(); // valid
bin(); // ReferenceError "bin is not defined"

因此,如果您的偏好是将函数提升到顶部,请使用function declaration其他方式使用expression. 我更喜欢后者,因为我通常使用 as 方法构建对象文字function expressions

function expressions当抛出错误时,命名会很方便。控制台会告诉你函数是什么,而不是说明anonymous又名堆栈跟踪

请记住,块中的函数声明在技术上无效的,因此最好使用函数表达式。
2021-04-18 11:52:03
@JesseGood——块内的函数声明根本不是“技术上无效的”,如果它们是,它们会抛出语法错误。没有充分的理由更喜欢函数表达式而不是声明,因为两者可以互换(注意有些情况下允许函数表达式但不允许声明)。
2021-04-26 11:52:03
哇,很明显,“函数声明”不应该在 javascript 中存在/被特殊对待——它们应该只是一个表达式,比如“命名函数表达式”,其返回值被忽略。
2021-05-07 11:52:03
@JesseGood——是的,我的意思是在if块内。我会解决这个问题的。
2021-05-09 11:52:03
这是一个经常被遗忘的重要区别:“当抛出错误时,命名函数表达式会很方便。控制台会告诉你函数是什么,而不是声明匿名的堆栈跟踪。”
2021-05-14 11:52:03

您在这里遇到了几个不同的问题,但我会先尝试解决您的主要问题。

一般来说....

function() { ... }是一个函数表达式从语法上讲,这与2or处于同一级别[4,5]这代表一个因此var foo=function(){ ... },每次都会按计划进行。

function foo() { ... } 是一个函数声明。这似乎与 做同样的事情var foo=function(){...},但有一个小警告。作为声明,它的工作原理类似于 JS 中变量提升的概念(基本上,所有变量声明都在计算任何表达式之前完成)。

一个很好的例子来自这里

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

基本上变量提升已将值提升到顶部,因此此代码等效(理论上)为:

function test() {
    var foo;//foo hoisted to top
    var bar=function(){//this as well
        alert("this will run!");
    }

    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
}

注意:我想借此机会说 JS 解释器很难遵循理论,因此不建议相信他们的某些不确定行为。在这里,您会在理论和实践最终不起作用的部分末尾找到一个很好的示例(还有一些关于表达式与声明主题的更多详细信息)。

有趣的事实:function foo() {...}用括号将其从声明转换为表达式,这可能会导致一些看起来很奇怪的代码,例如

(function foo() { return 1; })();// 1
foo; //ReferenceError: foo is not defined

如果没有理由,请不要这样做。


总结 var foo=function(){ ... }* 有点 * 与函数相同,foo(){ ... }除了前者做你认为它应该做的事情,而后者做奇怪的事情,除非你把它包在括号里,但这会弄乱范围,而 JS 解释器允许你做一些在规范中被认为是语法错误的事情,所以你会相信错误的事情实际上是正确的,等等......

请使用函数表达式( var f=function(){...})。没有真正的理由不这样做,特别是考虑到您在使用点语法时有些被迫这样做。


关于你接触的第二件事......

我真的不知道该说什么,这有点与其他所有事情完全不同。

var foo = {
    baz: 43,
    doSomething:function() {
        ...
    }
}

这称为对象字面量语法。基于此语法的 JSON 是一种非常简洁的数据格式化方式,并且 JS 中的此语法通常用于声明新对象,例如单例对象(避免声明函数和使用 new 的所有混乱) . 它也可以以与使用 XML 相同的方式使用,并且是所有酷孩子的首选......

无论如何,基本上对象字面量语法是这样工作的:

{ name1: val1, .... namek:valk }

这个表达式是一个对象,上面有一些初始化的值。这样做var obj={ name1: val1, .... namek:valk }意味着:

obj.name1==val1;
obj['name1']==val1;// x['y'] is the same thing as x.y 
...
obj.namek==valk;

那么这和我们的例子有什么关系呢?基本上,您的表达式通常用于声明单例对象。但是它也可以用来声明一个对象原型,所以以后有人可以做 var newObj=Object.create(foo) ,而 newObj 将以 foo 作为原型。

如果您想真正了解原型继承的有用性,请详细研究它。道格拉斯·克罗克福德(Douglas Crockford)在他的众多演讲之一中详细谈到了这一点)。

这是一篇简短的文章,提供了一些细节。也许不完全相似,但我认为 JSON 标记和 JS 语言(或任何语言)之间的关系类似于 HTML 标记和 DOM 之间的关系。一种是可以解析并呈现到另一种的标记。
2021-04-16 11:52:03
通常,如果您在 JavaScript 代码中定义对象字面量,我们不会将其称为 JSON,因为其余的 JS 代码使其成为无效的 JSON。相反,如果我们删除所有 JS,而只有一个独立的 JSON 结构{"foo":"bar"}(因为 JSON 键必须双引号),则这不构成有效的 JavaScript 程序。结果将是SyntaxError此外,JavaScript 字符串中允许存在一些不可见字符,但 JSON 不允许。总的来说,JS 和 JSON 之间的唯一联系是前两个字母,以及数据结构一般语法。
2021-04-25 11:52:03
请注意,我已尝试正确更改对 JSON 的引用。你有一个 JSON 的例子,它不是有效的文字语法,反之亦然?
2021-04-30 11:52:03
var foo = {...示例不是 JSON 语法。它是对象字面量语法。JSON 的数据结构符号基于JavaScript 的对象和数组字面量结构,但它们不是一回事。
2021-05-09 11:52:03
rtpg,您很好地解释了差异,并且强烈建议使用函数表达式。但是,您这样做的原因是:“没有理由不这样做”。持相反意见的人不会被说服。只有已经同意你的人才会同意。我的建议是展示几个例子,说明如果有人使用函数声明会有什么坏处。
2021-05-13 11:52:03

命名函数的好处很少

  • 元分析的名称。functionInstance.name会告诉你名字。
  • 更重要的是,名称将打印在堆栈跟踪中。
  • 名称还有助于编写自文档化或文字代码。

命名函数表达式有一个缺点

  • IE 有 NFE 的内存泄漏

除了较少的风格控制之外,函数声明没有任何缺点

IE<9。较旧的 JScript 引擎,还有 Saf 2.1、旧歌剧、旧 Firefox。阅读 NFE 文章
2021-04-24 11:52:03

您的问题实际上由两部分组成,因为如果将函数分配给变量或属性,则不必使它们匿名。

命名还是匿名?

@Raynos 清楚地突出了要点。命名函数最好的部分是它们会在堆栈跟踪中显示自己。即使在函数被分配给变量/属性的情况下,给你的函数一个名字只是为了帮助调试也是一个好主意,但是我不会说匿名函数是邪恶的。它们确实有很好的用途:

匿名函数在 JavaScript 中是一种不好的做法吗?

函数声明与函数表达式?

对于问题的那部分,我会向您推荐这个问题,因为它可能比我能更深入地涵盖该主题

var functionName = function() {} vs function functionName() {}