簡體   English   中英

JavaScript 函數順序:為什么重要?

[英]JavaScript function order: why does it matter?

原問題:

當我的 JavaScript 調用一個定義在頁面下方而不是調用它的函數時, JSHint 會抱怨。 但是,我的頁面是用於游戲的,在下載整個內容之前不會調用任何函數。 那么為什么訂單函數會出現在我的代碼中呢?

編輯:我想我可能已經找到了答案。

http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

我在里面呻吟。 看起來我需要再花一天時間重新排序 6000 行代碼。 使用 javascript 的學習曲線一點也不陡峭,但它非常棒。

tl;dr如果你在一切加載之前都不打電話,你應該沒問題。


編輯:有關還涵蓋一些 ES6 聲明( letconst )的概述: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet

這種奇怪的行為取決於

  1. 你如何定義函數和
  2. 當你打電話給他們時。

這里有一些例子。

bar(); //This won't throw an error
function bar() {}

foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
    foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
    foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
    foo(); //no error
}
var foo = function() {}
bar();

這是因為所謂的提升

定義函數有兩種方式:函數聲明和函數表達式 區別很煩人而且很細微,所以讓我們說這有點錯誤:如果你像function name() {}一樣寫它,它是一個聲明,當你像var name = function() {} (或分配給返回的匿名函數,諸如此類),它是一個函數表達式

首先,讓我們看看變量是如何處理的:

var foo = 42;

//the interpreter turns it into this:
var foo;
foo = 42;

現在,如何處理函數聲明

var foo = 42;
function bar() {}

//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;

var語句將foo創建“拋出”到最頂部,但尚未為其分配值。 函數聲明緊隨其后,最后為foo分配了一個值。

而這個呢?

bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;

只有foo聲明被移到頂部。 分配僅在調用bar之后出現,在所有提升發生之前。

最后,為了簡潔起見:

bar();
function bar() {}
//turns to
function bar() {}
bar();

現在,函數表達式呢?

var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();

就像普通變量一樣,首先在作用域的最高點聲明foo ,然后給它賦值。

讓我們看看為什么第二個例子會拋出錯誤。

bar();
function bar() {
    foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
    foo();
}
bar();
foo = function() {}

正如我們之前看到的,只有foo的創建被提升,賦值出現在它出現在“原始”(未提升)代碼中的地方。 bar被調用時,它是在foo被賦值之前,所以foo === undefined 現在在bar的函數體中,就好像您在執行undefined() ,這會引發錯誤。

主要原因可能是 JSLint 只對文件執行一次傳遞,因此它不知道您定義這樣的函數。

如果您使用了函數語句語法

function foo(){ ... }

實際上在聲明函數的地方沒有任何區別(它總是表現得好像聲明在開頭)。

另一方面,如果您的函數設置為常規變量

var foo = function() { ... };

您必須保證在初始化之前不會調用它(這實際上可能是錯誤的來源)。


由於重新排序大量代碼很復雜,並且本身可能是錯誤的來源,我建議您尋找一種解決方法。 我很確定你可以事先告訴 JSLint 全局變量的名稱,這樣它就不會抱怨未聲明的東西。

對文件的開頭發表評論

/*globals foo1 foo2 foo3*/

或者您可以在那里使用文本框。 (我也認為你可以在參數中將它傳遞給內部 jslint 函數,如果你能插手的話。)

有太多人在推行關於 JavaScript 應該如何編寫的任意規則。 大多數規則是徹頭徹尾的垃圾。

函數提升是 JavaScript 的一個特性,因為它是一個好主意。

當您有一個內部函數通常是內部函數的效用時,將它添加到外部函數的開頭是一種可以接受的編寫代碼的風格,但它確實有一個缺點,即您必須通讀細節才能得到什么外部函數確實如此。

您應該在整個代碼庫中堅持一個原則,要么將私有函數放在模塊或函數中,要么放在最前面,要么放在最后。 JSHint 有利於增強一致性,但您應該絕對調整 .jshintrc 以滿足您的需要,而不是將您的源代碼調整為其他人古怪的編碼概念。

您可能會在野外看到的一種編碼風格應該避免,因為它沒有任何優勢,只會給您帶來重構的痛苦:

function bigProcess() {
    var step1,step2;
    step1();
    step2();

    step1 = function() {...};
    step2 = function() {...};
}

這正是函數提升要避免的。 只需學習語言並發揮其優勢即可。

只有函數聲明被提升,而不是函數表達式(賦值)。

暫無
暫無

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

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