当我使用“传统”C风格的函数声明时,JavaScript中发生了什么?

时间:2010-09-26 17:33:11

标签: javascript function

我知道有几种方法可以在JavaScript中定义一个函数。其中两个最常见的是:

(1)  function add (a, b) {
         return a + b;
     }

(2)  var add = function (a, b) {
         return a + b;
     }

我觉得将函数作为一个对象的想法可以像任何其他变量一样传递。所以我完全理解(2)正在做什么。它正在创建一个函数并分配给add(假设这是在全局范围内,因此add是一个全局变量)所述函数。但是如果我使用(1)而发生了什么呢?我已经知道它在执行顺序上有所不同:如果我使用(1),那么我可以在代码中定义add()的点之前引用add(),但是如果我使用{ {1}}然后我必须先将我的功能分配给(2),然后再开始引用add

add()只是(1)的一个快捷方式,虽然它恰好像其他C风格的语言一样,允许我们定义一个“低于”它使用点的函数吗?或者它内部是一种不同类型的功能?哪个更符合JavaScript的“精神”(如果这个术语不是太模糊)?你会把自己限制在一个或另一个,如果是这样的话吗?

2 个答案:

答案 0 :(得分:6)

看起来您已经了解 function declarations 1 (1)和 function expressions (2)。另请注意,在(1)中仍然存在一个名为add的局部变量,其中包含一个函数值,就像在(2)中一样:

function hello () {
   alert('Hello World');
}

console.log(typeof hello);  // prints "function"

setTimeout(hello, 1000);    // you can still pass functions around as arguments,
                            // even when using function declarations.

值得一提的另一点是函数声明(1)不应该用于有条件地定义函数(例如在if语句中),因为正如您所提到的,它们是由JavaScript解释器 2 自动移动到包含范围的顶部。这通常称为 hoisting

至于哪种方法更符合JavaScript的精神,我更喜欢使用函数表达式(2)。对于更权威的意见,Douglas Crockford列出了他的流行The Good Parts book 2 的“坏部分”章节中的函数声明(1)。


1 也称为函数语句(参见下面的@Tim Down's条评论)。
2 实际上有些浏览器能够在if语句中处理函数声明(再次参考下面的评论)。
3 JavaScript: The Good Parts - 附录B:第113页。

答案 1 :(得分:2)

function foo() {};
foo.toString() //-> "function foo() {}"

var bar = foo;
bar.toString() //-> "function foo() {}"

因此它声明了一个命名函数。无论变量指向哪个变量,都会保留其名称。使用另一种语法是匿名函数,它是无名的,只有在变量引用时才能被访问。

var foo = function() {};
foo.toString() //-> "function () {}"

var bar = foo;
bar.toString() //-> "function () {}"

就使用哪种风格而言,没有主要规则。虽然我个人赞成匿名语法,因为它提醒我函数确实是可以传递的对象。我也倾向于赞成“它只是一个大主对象”的方法,这要求以这种方式声明函数。

var MyThingy = {
  foo: function() { alert('foo') },
  bar: function() { MyThingy.foo() }
}

但是在创建函数之后,差异并不重要且行为相同。但是匿名语法在你提到的魔术之前的扫描量较少,而且复杂代码和奇怪的作用域情况下的错误更少。