缺少分号时Javascript未定义类函数

Far*_*her 3 javascript

function Foo() {
    var that = this;
    that.bar = function() {}
    that.baz = function() {}

    (function() {
        that.baz();
    }());
}
new Foo;
Run Code Online (Sandbox Code Playgroud)

Uncaught TypeError: Object #<Foo> has no method 'baz'

that.bar工作正常,它只是最后一个不存在的功能.;baz函数定义之后添加一个修复所有内容.

我知道排除;可以弄乱一些事情,但我认为你肯定不应该放弃;功能.没有语言可以做到.为什么;baz函数之后排除导致此错误?我应该;在我的功能定义之后吗?

ick*_*fay 9

相反,迈克尔·吉尔的回答,赋值语句并不需要分号.

考虑一下简单的立即调用的函数表达式:

(function() { /* do something */ })();
Run Code Online (Sandbox Code Playgroud)

包裹function() { ... }for 的额外括号是什么?它们是为了防止它被解释为函数定义,迫使它被解释为函数表达式.它基本上等同于此,但不创建另一个变量:

var temp = function() { /* do something */ };
temp();
Run Code Online (Sandbox Code Playgroud)

但括号只是引入必须表达的东西的一种方式.特别是,赋值语句的初始值设定项将引入表达式1:

someVar = /* what goes here must be an expression */;
Run Code Online (Sandbox Code Playgroud)

显然,撰写这些概念表明:

someVar = (function() { return 5; })();
Run Code Online (Sandbox Code Playgroud)

实际上并不需要包裹括号!我们可以很容易地写这个,因为function()它不能被解释为函数定义:

someVar = function() { return 5; } ();
Run Code Online (Sandbox Code Playgroud)

那么这与分号有什么关系呢?事实证明,如果下一行可以继续语句或表达式,它将会.2你写的这个:

that.baz = function() {}

(function() {
    that.baz();
}());
Run Code Online (Sandbox Code Playgroud)

有了这些知识,你知道它实际上被解释为:

that.baz = (function() {})(function() {
    that.baz();
}());
Run Code Online (Sandbox Code Playgroud)

这有点棘手,所以这就是发生的事情:

  1. 首先,function() {}评估(执行),产生一个函数对象.
  2. 然后调用此函数对象,但等待!在我们开始正确执行之前,我们必须先评估一些参数.
  3. 唯一的论点是表达式

    function() {
        that.baz();
    }()
    
    Run Code Online (Sandbox Code Playgroud)

    这显然是一个立即调用的函数表达式,所以我们将开始执行它.

  4. 我们试图找到that.baz并调用它,但它失败了,因为that.baz不存在因此解决了undefined!不好了!JavaScript引擎在这里停止,因为抛出了未捕获的异常,但为了清楚起见,让我们假装它继续.
  5. 我们从未返回任何东西function() { that.baz(); },所以争论function() {}undefined.
  6. 我们现在function() {}正确执行.它永远不会束缚它的论点,所以它undefined被忽略了.它不会返回任何内容,因此调用会产生undefined.
  7. 现在我们已经完成了对该表达式的评估!我们将that.baz结果,undefined.

希望您现在看到解析器误将您的立即调用的函数表达式误解为另一个匿名函数的参数,并立即调用.

怎么预防呢?

如前所述,括号不是明确引入表达式的唯一方法.事实上,当他们无意中处于表达的中间时,它可能会导致这样的问题.我们还提到了作业,但我们不想分配一些东西.

还剩什么?一元运营商.我们可以使用一些.我喜欢!,所以我们会用它.而不是使用:

(function() {
    that.baz();
}());
Run Code Online (Sandbox Code Playgroud)

我们用:

!function() {
    that.baz();
}();
Run Code Online (Sandbox Code Playgroud)

!只能来自于一种表达的开始,所以开始的JavaScript解析表达式.之后只能有一个表达式!,因此该函数被解析为函数表达式而不是函数定义.由于优先级,首先调用该函数.它不返回任何东西,所以它返回undefined.undefined是假的,所以!翻转和收益true.由于我们从未对此表达式的结果做任何事情,因此将true被丢弃.(如果我们返回一个真正的值,它就不重要;然后!就会产生false并且会被丢弃.无论如何,它都会被丢弃.)

TLDR:对IIFE使用一元运算符而不是括号.


脚注

1 从技术上讲,赋值是一种表达,而不是一种陈述,但对于我们的目的而言,它并不重要.
2随着外return,continue,break,和类似表述哪里会迷惑很多更多的混乱.


Mic*_*ary 5

函数声明后不需要分号:

function foo() {
}
Run Code Online (Sandbox Code Playgroud)

如果你添加分号没有任何伤害,你只需要它:

function foo() {
};
Run Code Online (Sandbox Code Playgroud)

在函数声明后插入一个空语句,该语句无效.以同样的方式,除了让阅读代码的人感到困惑之外,这不会造成任何伤害:

var i = 1;;;;;;;;;;;;;;;;;;;;;;;;;;
Run Code Online (Sandbox Code Playgroud)

OTOH,你这样做需要一个赋值语句后分号:

that.prop = 1;
Run Code Online (Sandbox Code Playgroud)

如果您分配的值是函数表达式,则不会更改:

that.foo = function() {};
Run Code Online (Sandbox Code Playgroud)

  • 不,您不需要在赋值语句后 ** 需要** 分号。在极少数情况下**需要**它们。http://mislav.uniqpath.com/2010/05/semicolons/。应该鼓励一致性 (2认同)