鍍金池/ 問答/HTML/ 如何理解ESLint的no-inner-declarations規(guī)則?(不建議在

如何理解ESLint的no-inner-declarations規(guī)則?(不建議在{}代碼塊內部聲明變量或函數(shù))

如下代碼:

if (true) {
    // 在某個條件分支下創(chuàng)建一個函數(shù),并且只在這個分支內使用。
    function a() {
        // code...
    }
    a();
}
// 報錯:
"Move function declaration to program root. (no-inner-declarations)"

要把函數(shù)定義在整個文檔的最外層才行。我在網(wǎng)上搜索看到的說法是:

ES6以前,函數(shù)聲明只能在程序或另一個函數(shù)體的最前面,所以在代碼塊內部聲明函數(shù)是錯誤的做法。另外,由于 javascript 中代碼聲明會被提升到代碼當前作用域的最前面,所以在代碼塊內聲明變量也是不明智的做法

是不是在ES6之前,這樣聲明是語法錯誤?另外,我會把這個函數(shù)保持在它被調用之前,這樣就不會發(fā)生變量提升了。

其實我很郁悶,因為我的代碼要根據(jù)不同場景執(zhí)行不同的代碼,有些函數(shù)只在某一個場景下使用。按照這個標準的話要把大量函數(shù)移出來,結果就是聲明的這些函數(shù)有很多根本沒有被調用。這樣是不是會多占用資源?

回答
編輯回答
萌吟

1、題主第一個問題:想這樣:

在某個條件分支下創(chuàng)建一個函數(shù),并且只在這個分支內使用。

所以寫出下面代碼:

if (true) {
    // 在某個條件分支下創(chuàng)建一個函數(shù),并且只在這個分支內使用。
    function a() {
        // code...
    }
    a();
}

但是,題主如果在 if 語句塊之外訪問函數(shù) a,是可以的,因為

ES6 在非嚴格模式下塊級函數(shù)的作用域會被提升到所在函數(shù)或全局環(huán)境的頂部,而不是代碼塊的頂部。

所以下面代碼不會報錯:

if (true) {
    // 在某個條件分支下創(chuàng)建一個函數(shù),并且只在這個分支內使用。
    function a() {
        // code...
    }
    a();
}
a;//返回函數(shù) a 

所以,題主想要的

在某個條件分支下創(chuàng)建一個函數(shù),并且只在這個分支內使用

非嚴格模式下,并沒有實現(xiàn),或者說,看起來實現(xiàn)了,但實際上沒有,反而造成了全局變量污染且容易引起歧義;

嚴格模式下,是實現(xiàn)了的,也就是說,上面的函數(shù) a 只能在 if 語句塊內訪問,因為

ES6 會將 a() 函數(shù)視為塊級聲明,并允許它在定義所在的代碼塊內部被訪問,且塊級函數(shù)會被提升到所在代碼塊的頂部

2、題主的第二個問題:

是不是在ES6之前,這樣聲明是語法錯誤?

答:

在 ES3 或更早版本中,在代碼塊中聲明函數(shù)(即塊級函數(shù))嚴格來說應當是一個語法錯誤,但所有的瀏覽器卻都支持該語法??上У氖?,每個支持該語法的瀏覽器都有輕微的行為差異,所以最佳實踐就是不要在代碼塊中聲明函數(shù)(更好的選擇是使用函數(shù)表達式)。

為了控制這種不兼容行為, ES5 的嚴格模式為代碼塊內部的函數(shù)聲明引入了一個錯誤

3、題主的第三個問題:

另外,我會把這個函數(shù)保持在它被調用之前,這樣就不會發(fā)生變量提升了。

題主請先去了解下函數(shù)聲明語句的變量提升,題主的這句話代表題主并不理解變量提升;

clipboard.png

4、題主的第四個問題:

其實我很郁悶,因為我的代碼要根據(jù)不同場景執(zhí)行不同的代碼,有些函數(shù)只在某一個場景下使用。按照這個標準的話要把大量函數(shù)移出來,結果就是聲明的這些函數(shù)有很多根本沒有被調用。這樣是不是會多占用資源?

這個不太清楚,我粗淺的認為不會,因為 js 有垃圾回收機制,如果沒有閉包,正常情況下都會被垃圾回收掉的,閉包題主請單獨查資料,或者戳這

參考:深入理解ES6-中-非掃描版

2017年5月23日 18:30
編輯回答
玄鳥

重新回答一份

1.ESLint只是一個代碼檢查工具,它報錯不代表代碼是錯誤的
2.ESLint的提示都是有原因的
3.在代碼塊兒中定義函數(shù)自己使用的做法很常見,不喜歡提示可以關掉這個選項
4.如果“提升”整個概念是指編譯階段將所有的聲明都挪到執(zhí)行代碼的前面,那我可以接受。為什么會將聲明的部分提到最前面,我覺得應該是方便申請內存吧。
5.我也不支持在代碼塊(尤其是邏輯分支)中定義自己使用的函數(shù)。如果你能確定這個方法絕對沒有地方再使用,大可這么做,語法也支持,協(xié)作起來也只有你自己知道這段代碼并維護。
6.方法定義在哪里都一樣,代碼體積也不會變,也省不了多少內存。在邏輯分支里定義了函數(shù)基本上也會馬上調用,理論上修改起來并不方便。

寫在后面:這個語法是沒有錯誤的,但是是存在的隱患的,所以ESLint告訴你不要這么做。你擔心的占用資源問題是多余的,方法執(zhí)行起來占用的資源才是你應該擔心的。另外考慮到復用性和協(xié)作,即使是不同分支要執(zhí)行不同代碼,也不要在代碼塊兒內聲明方法。復用性上不便于方法的復用,協(xié)作性上不便于別人修改你的代碼。如果說需求是根據(jù)不同的條件需要不同的方法體,那為什么不把這個條件作為參數(shù)傳入方法,在方法體中進行邏輯分支。ESLint給出的提示是根據(jù)設計模式和代碼規(guī)范給出的,完全按照提示去做絕對沒有壞處,不按照他說的做也不一定會報錯。養(yǎng)成良好的代碼習慣,學會去構建代碼,而不是一味地實現(xiàn)邏輯,這也是ESLint這樣的工具存在的目的。

2017年1月20日 10:16