69

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

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

var foo=函数(){…}

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

变量foo={baz:43,doSomething:函数(){// ...}}

函数foo(){// ... }

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

4个答案4

重置为默认值
90

这一切都取决于您声明函数的位置;吊装。

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

函数foo(){bar();var x=1;}

实际上是这样解释的:

函数foo(){变量x;bar();x=1;}

请注意,声明的赋值部分没有被挂起。只有名字被悬挂起来。函数声明的情况并非如此,整个函数体也将被吊起。

功能测试(){foo();//TypeError“foo不是函数”bar();//“这会跑的!”var foo=赋给局部变量“foo”的函数(){//函数表达式alert(“这不会运行!”);}function bar(){//函数声明,名称为“bar”alert(“这将运行!”);}}测试();

在这种情况下,只有函数声明的主体被提升到顶部。名称“foo”被提升,但主体被留在后面,以便在执行过程中分配。

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

foo();//TypeError“foo不是函数”bar();//有效的baz();//TypeError“baz不是函数”bin();//ReferenceError“未定义箱子”var foo=函数(){};//匿名函数表达式('foo'被提升)函数bar(){};//函数声明('bar'和函数体被提升)var baz=函数bin(){};//命名函数表达式(仅提升“baz”)foo();//有效的bar();//有效的baz();//有效的bin();//ReferenceError“未定义箱子”

因此,如果您喜欢将函数提升到顶部,请使用函数声明否则使用表达。我更喜欢后者,因为我通常使用如下方法构建对象文本函数表达式.

命名函数表达式当抛出错误时可以很方便。控制台将告诉您该函数是什么,而不是声明匿名的阿卡堆栈跟踪.

8
  • 4
    只需记住块中的函数声明是技术上无效,因此最好使用函数表达式。 评论 2012年4月10日1:22
  • 1
    哇,很明显,“函数声明”不应该在javascript中存在/被专门处理——它们应该只是一个表达式,比如“命名函数表达式”,其返回值被忽略。 评论 2014年6月2日20:11
  • @JesseGood-ah是的,我是说里面如果阻碍。我会解决的。
    – 罗布·G
    评论 2016年5月18日23:04
  • @块中的JesseGood-function声明在技术上根本不是无效的,如果是这样的话,它们会抛出语法错误。没有充分的理由选择函数表达式而不是声明,在声明中两者可以互换(注意,在某些情况下,函数表达式是允许的,但声明是不允许的)。
    – 罗布·G
    评论 2016年5月18日23:04
  • 2
    这是一个经常被遗忘的重要区别:“当抛出错误时,命名函数表达式可能很方便。控制台将告诉您函数是什么,而不是声明匿名aka堆栈跟踪。” 评论 2018年12月1日19:54
11

你在这里碰到了几个不同的问题,但我会先回答你的主要问题。

一般来说。。。。

函数(){…}是一个函数表达式从语法上来说,这与2[4,5]。这表示价值.这么做var foo=函数(){…}每次都会按计划进行。

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

一个很好的例子来自在这里:

功能测试(){foo();//TypeError“foo不是函数”bar();//“这会跑的!”var foo=赋给局部变量“foo”的函数(){//函数表达式alert(“这不会运行!”);}function bar(){//函数声明,名称为“bar”alert(“这将运行!”);}}测试();

基本上,可变起重已将值提升到最高,因此该代码是等效的(理论上)收件人:

功能测试(){变量foo//foo吊装至顶部var bar=function(){//这也是alert(“这将运行!”);}foo();//TypeError“foo不是函数”bar();//“这会跑的!”var foo=赋给局部变量“foo”的函数(){//函数表达式alert(“这不会运行!”);}}

注:我想借此机会说,JS口译员很难理解理论,所以不建议相信他们有点可疑的行为。在这里在一节的末尾,您会发现一个很好的例子,理论和实践最终都不起作用(还有关于表达式与声明主题的更多细节)。

有趣的事实:包装函数foo(){…}在括号中,将它从声明转换为表达式,这可能会导致一些奇怪的代码,如

(函数foo(){return 1;})();//1foo//ReferenceError:未定义foo

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


总结 var foo=函数(){…}有点像函数吗foo(){…}除了前者做了你认为应该做的事情,而后者做了奇怪的事情,除非你把它包装在parens中,但这弄乱了范围,JS解释器允许你做规范中被认为是语法错误的事情,所以你会认为错误的事情实际上是正确的,等等。。。。

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


关于你碰到的第二件事。。。。。

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

变量foo={baz:43,doSomething:函数(){...}}

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

无论如何,基本上对象文字语法的工作原理如下:

{name1:val1,….namek:valk}

这个表达式是一个对象,上面初始化了某些值var对象={name1:val1,….namek:valk}意味着:

obj.name1==val1;对象['name1']==val1;//x['y']和x.y是一回事...对象名称==valk;

那么这与我们的例子有什么关系呢?基本上,表达式通常用于声明单例对象。但它也可以用于声明对象原型,因此有人可以稍后执行var newObj=object.create(foo),newObj将foo作为原型。

如果你想真正了解它的用处,请仔细研究原型继承。道格拉斯·克罗克福德在他多次演讲中)。

6
  • 1
    这个var foo={。。。示例不是JSON语法。这是对象文字语法。JSON的数据结构符号为基于JavaScript的对象和数组文字结构,但它们不是一回事。
    – 用户1106925
    评论 2012年4月10日2:28
  • 注意,我已尝试正确更改对JSON的引用。你有一个JSON的例子,它不是有效的文本语法,还是vise-versa? 评论 2012年4月10日2:35
  • 1
    通常,如果您在JavaScript代码中定义对象文字,我们不会将其称为JSON,因为JS代码的其余部分使其成为无效的JSON。相反,如果我们删除所有JS,只需要一个独立的JSON结构,如{“foo”:“bar”}(由于JSON键必须是双引号),这并不构成有效的JavaScript程序。结果将是语法错误此外,JavaScript字符串中允许使用一些不可见字符,但JSON中不允许使用。总的来说,JS和JSON之间的唯一联系是前两个字母一般的数据结构的语法。
    – 用户1106925
    评论 2012年4月10日3:20
  • 这里有一个短文这提供了一些细节。也许不完全类似,但我认为JSON标记和JS语言(或任何语言)之间的关系类似于HTML标记和DOM之间的关系。一个是可以解析并呈现到另一个中的标记。
    – 用户1106925
    评论 2012年4月10日3:24
  • rtpg,您很好地解释了区别,并且您强烈建议使用函数表达式。然而,你这样做的理由是:“没有理由不这样做”。持反对意见的人不会被说服。只有已经同意你的人才会同意。我的建议是展示几个例子,说明如果有人使用函数声明会有什么不好。 评论 2015年5月2日1:01
2

命名函数没有什么优点

  • 元分析的名称。函数实例名称将显示名称。
  • 更重要的是,名称将打印在堆栈跟踪中。
  • 名字也有助于编写自我记录或识字代码。

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

  • IE有NFE的内存泄漏

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

1
  • IE<9。旧的JScript引擎,还有Saf 2.1,旧的opera,旧的firefox。阅读NFE文章
    – 雷诺斯
    评论 2012年4月10日2:39
1

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

命名vs匿名?

@雷诺斯清楚地强调了要点。命名函数最棒的地方是它们将在堆栈跟踪中显示自己。即使在将函数分配给变量/属性的情况下,也最好给函数起一个名称,以帮助调试,但我并不认为匿名函数是邪恶的。它们确实有很好的用途:

匿名函数在JavaScript中是一种坏习惯吗?

函数声明与函数表达式?

对于这个问题的这一部分,我想请你参考这个问题,因为它可能比我能涵盖的主题更深入

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

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.