簡體   English   中英

缺少分號時Javascript未定義類函數

[英]Javascript undefined class function when missing semicolon

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

    (function() {
        that.baz();
    }());
}
new Foo;

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

that.bar工作正常,它只是最后一個不存在的函數。 添加; baz函數定義之后修復了所有內容。

我知道排除; 可以弄亂一些東西,但我想你肯定不應該放; 功能之后。 沒有語言可以做到。 為什么要排除; baz函數導致這個打破之后? 我應該放; 在我的函數定義之后?

相反, 邁克爾·吉爾的回答 ,賦值語句不需要分號。

考慮一下簡單的立即調用的函數表達式:

(function() { /* do something */ })();

包含function() { ... }的額外括號是什么? 它們是為了防止它被解釋為函數定義 ,迫使它被解釋為函數表達式。 它基本上等同於此,但不創建另一個變量:

var temp = function() { /* do something */ };
temp();

但括號只是引入必須表達的東西的一種方式。 特別是, 賦值語句的初始值設定項將引入表達式 1

someVar = /* what goes here must be an expression */;

顯然,撰寫這些概念表明:

someVar = (function() { return 5; })();

實際上並不需要包裹括號! 我們可以很容易地寫這個,因為function()不能被解釋為函數定義:

someVar = function() { return 5; } ();

那么這與分號有什么關系呢? 事實證明,如果下一行可以繼續語句或表達式,它將會。 2你寫的這個:

that.baz = function() {}

(function() {
    that.baz();
}());

有了這些知識,你知道它實際上被解釋為:

that.baz = (function() {})(function() {
    that.baz();
}());

這有點棘手,所以這就是發生的事情:

  1. 首先,評估( 執行) function() {} ,產生一個函數對象。
  2. 然后調用此函數對象, 但等待 在我們開始正確執行之前,我們必須先評估一些參數。
  3. 唯一的論點是表達式

     function() { that.baz(); }() 

    這顯然是一個立即調用的函數表達式,所以我們將開始執行它。

  4. 我們試圖找到that.baz並調用它,但它失敗了,因為that.baz不存在,因此解析為undefined 不好了! JavaScript引擎在這里停止,因為拋出了未捕獲的異常,但為了清楚起見,讓我們假裝它繼續。
  5. 我們從來沒有從function() { that.baz(); } function() { that.baz(); } ,所以參數function() {}undefined
  6. 我們現在正確執行function() {} 它永遠不會綁定它的參數,因此忽略undefined 它不返回任何內容,因此調用導致undefined
  7. 現在我們已經完成了對表達式的評估! 我們將that.baz設置為結果, undefined

希望您現在看到解析器誤將您的立即調用的函數表達式誤解為另一個匿名函數的參數,並立即調用

怎么預防呢?

如前所述,括號不是明確引入表達式的唯一方法。 事實上,當他們無意中處於表達的中間時,它可能會導致這樣的問題。 我們還提到了作業,但我們不想分配一些東西。

還剩什么? 一元運營商。 我們可以使用一些。 我喜歡! 所以我們會用它。 而不是使用:

(function() {
    that.baz();
}());

我們用:

!function() {
    that.baz();
}();

! 只能在表達式的開頭出現,因此JavaScript開始解析表達式。 只有一個表達才可以追隨! ,因此該函數被解析為函數表達式而不是函數定義。 由於優先級,首先調用該函數。 它不返回任何內容,因此返回undefined undefined是假的,所以! 翻轉它並產生true 由於我們從未對此表達式的結果執行任何操作,因此將丟棄true (如果我們返回一個真正的值,那就不重要了;那么!會產生false而且會被丟棄。無論如何,它都會被丟棄。)

TLDR:對IIFE使用一元運算符而不是括號。


腳注

1 從技術上講 ,賦值是一種表達,而不是一種陳述,但對於我們的目的而言,它並不重要。
2隨着外returncontinuebreak ,和類似表述它會混淆更加混亂。

函數聲明后不需要分號:

function foo() {
}

如果你添加分號沒有任何傷害,你只需要它:

function foo() {
};

在函數聲明后插入一個空語句,該語句無效。 以同樣的方式,除了讓閱讀代碼的人感到困惑之外,這不會造成任何傷害:

var i = 1;;;;;;;;;;;;;;;;;;;;;;;;;;

OTOH, 需要一個賦值語句后分號:

that.prop = 1;

如果您分配的值是函數表達式,則不會更改:

that.foo = function() {};

這也行

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

    (function() {
        that.baz();
    }());
}
new Foo;

得到它?

他們是兩個陳述。 他們需要兩個結局。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM