ES6 有什麼新功能? CoffeeScript 轉換透視圖

已發表: 2022-03-11

兩年多來,我一直是 CoffeeScript 的粉絲。 我發現我編寫 CoffeeScript 更有效率,少犯愚蠢的錯誤,並且支持源映射,調試 CoffeeScript 代碼完全輕鬆。

ES6 有什麼新功能? CoffeeScript 轉換透視圖

最近我一直在使用 Babel 玩 ES6,總的來說我是一個粉絲。 在本文中,我將從 CoffeeScript 轉換者的角度整理我在 ES6 上的發現,看看我喜歡的東西,看看我還缺少什麼。

句法上重要的縮進:是好事還是壞事?

我一直對 CoffeeScript 語法上重要的縮進有點愛/恨。 當一切順利時,你會得到“看,媽媽,沒有手!” 吹噓使用這種超簡約語法的權利。 但是當事情出錯並且不正確的縮進導致真正的錯誤時(相信我,它確實發生了),感覺這些好處是不值得的。

 if iWriteCoffeeScript if iAmNotCareful badThings = 'happen'

通常,當您的代碼塊包含一些嵌套語句時會導致這些錯誤,並且您不小心錯誤地縮進了一個語句。 是的,這通常是由眼睛疲勞引起的,但在我看來,它更有可能發生在 CoffeeScript 中。

當我開始編寫 ES6 時,我不太確定我的直覺會是什麼。 事實證明,再次開始使用花括號真的感覺非常好。 使用現代編輯器也有幫助,因為通常您只需要打開大括號,您的編輯器就會為您關閉它。 感覺有點像是在使用了 CoffeeScript 的巫術魔法之後回到了一個平靜、清晰的宇宙。

 if (iWriteES6) { if (iWriteNestedStatements) { let badThings = 'are less likely to happen' } }

當然,我堅持要去掉分號。 如果我們不需要它們,我會說把它們扔掉。 我覺得它們很醜,而且需要額外的打字。

課堂支持

ES6 中的類支持非常棒,如果您從 CoffeeScript 遷移過來,您會感到賓至如歸。 讓我們用一個簡單的例子來比較兩者的語法:

ES6 類

class Animal { constructor(numberOfLegs) { this.numberOfLegs = numberOfLegs } toString() { return `I am an animal with ${this.numberOfLegs} legs` } } class Monkey extends Animal { constructor(bananas) { super(2) this.bananas = bananas } toString() { let superString = super.toString() .replace(/an animal/, 'a monkey') return `${superString} and ${this.bananas} bananas` } }

CoffeeScript 類

class Animal constructor: (@numberOfLegs) -> toString: -> "I am an animal with #{@numberOfLegs} legs" class Monkey extends Animal constructor: (@numberOfBananas) -> super(2) toString: -> superString = super.toString() .replace(/an animal/, 'a monkey') "#{superString} and #{@numberOfLegs} bananas"

第一印象

您可能會注意到的第一件事是 ES6 仍然比 CoffeeScript 冗長得多。 CoffeeScript 中非常方便的一種快捷方式是支持在構造函數中自動分配實例變量:

 constructor: (@numberOfLegs) ->

這相當於 ES6 中的以下內容:

 constructor(numberOfLegs) { this.numberOfLegs = numberOfLegs }

當然,這並不是真正的世界末日,如果有的話,這種更明確的語法更容易閱讀。 另一個缺失的小事情是我們沒有@快捷方式, this在 Ruby 背景下總是感覺很好,但又不是一個大的交易破壞者。 總的來說,我們在這裡感覺很自在,實際上我更喜歡 ES6 語法來定義方法。

多麼超級!

在 ES6 中處理super的方式有一個小問題。 CoffeeScript 以 Ruby 的方式處理super (“請向同名的超類方法發送消息”),但是在 ES6 中唯一可以使用“裸”super 的情況是在構造函數中。 ES6 遵循更傳統的類似 Java 的方法,其中super是對超類實例的引用。

我會回來

在 CoffeeScript 中,我們可以使用隱式返回來構建漂亮的代碼,如下所示:

 foo = -> if Math.random() > 0.5 if Math.random() > 0.5 if Math.random() > 0.5 "foo"

在這裡,當您調用foo()時,您獲得“foo”的機會非常小。 ES6 沒有這些,並迫使我們使用return關鍵字返回:

 const foo = () => { if (Math.random() > 0.5 ) { if (Math.random() > 0.5 ) { if (Math.random() > 0.5 ) { return "foo" } } } }

正如我們在上面的示例中看到的,這通常是一件好事,但我仍然發現自己忘記添加它並且到處都得到意外的未定義返回! 我遇到了一個例外,關於箭頭函數,您可以在其中獲得一個像這樣的內襯的隱式返回:

 array.map( x => x * 10 )

這有點方便,但可能會有點混亂,因為如果添加花括號,您需要return

 array.map( x => { return x * 10 })

但是,它仍然是有道理的。 原因是如果你添加了花括號,那是因為你想使用多行,如果你有多行,那麼清楚你要返回的內容是有意義的。

ES6 類語法獎勵

我們已經看到,在定義類時,CoffeeScript 有一些句法技巧,但 ES6 也有它自己的一些技巧。

Getter 和 Setter

ES6 對通過 getter 和 setter 進行封裝具有強大的支持,如下例所示:

 class BananaStore { constructor() { this._bananas = [] } populate() { // fetch our bananas from the backend here } get bananas() { return this._bananas.filter( banana => banana.isRipe ) } set bananas(bananas) { if (bananas.length > 100) { throw `Wow ${bananas.length} is a lot of bananas!` } this._bananas = bananas } }

感謝getter,如果我們訪問bananaStore.bananas ,它只會返回成熟的香蕉。 這真的很棒,因為在 CoffeeScript 中,我們需要通過類似bananaStore.getBananas()的 getter 方法來實現它。 當在 JavaScript 中我們習慣於直接訪問屬性時,這感覺一點也不自然。 這也使開髮變得混亂,因為我們需要為每個屬性考慮我們應該如何訪問它 - 是.bananas還是getBananas()

setter 同樣有用,因為我們可以清理數據集,甚至在設置無效數據時拋出異常,如上面的玩具示例所示。 這對於任何具​​有 Ruby 背景的人來說都是非常熟悉的。

我個人認為這並不意味著你應該為所有事情都使用 getter 和 setter 來發瘋。 如果您可以通過 getter 和 setter(如上面的示例)封裝您的實例變量來獲得一些東西,那麼請繼續這樣做。 但是想像一下,您只有一個布爾標誌,例如isEditable 。 如果直接暴露isEditable屬性不會丟失任何東西,我認為這是最好的方法,因為它是最簡單的。

靜態方法

ES6 支持靜態方法,這讓我們可以做這個頑皮的把戲:

 class Foo { static new() { return new this } }

現在如果你討厭寫new Foo()你現在可以寫Foo.new() 。 純粹主義者會抱怨,因為new是一個保留字,但經過非常快速的測試後,它似乎在 Node.js 和現代瀏覽器中都能正常工作。 但是您可能不想在生產中使用它!

不幸的是,因為在 ES6 中不支持靜態屬性,如果你想定義類常量並在你的靜態方法中訪問它們,你必須做這樣的事情,這有點 hackish:

 class Foo { static imgPath() { return `${this.ROOT_PATH}/img` } } Foo.ROOT_PATH = '/foo'

有一個 ES7 Proposal 來實現聲明性實例和類屬性,這樣我們就可以做這樣的事情,這會很好:

 class Foo { static ROOT_PATH = '/foo' static imgPath() { return `${this.ROOT_PATH}/img` } }

這已經可以在 CoffeeScript 中非常優雅地完成:

 class Foo @ROOT_PATH: '/foo' @imgPath: -> @ROOT_PATH

字符串插值

我們終於可以在 Javascript 中進行字符串插值的時候到了!

 `I am so happy that in the year ${new Date().getFullYear()} we can interpolate strings`

來自 CoffeeScript/Ruby,這種語法感覺有點糟糕。 可能是因為我的 Ruby 背景,使用反引號來執行系統命令,一開始感覺很不對勁。 也使用美元符號感覺有點八十年代 - 但也許這只是我。

我想由於向後兼容性問題,不可能實現 CoffeeScript 樣式的字符串插值。 "What a #{expletive} shame"

箭頭函數

箭頭函數在 CoffeeScripter 中被認為是理所當然的。 ES6 幾乎實現了 CoffeeScript 的粗箭頭語法。 所以我們得到了一個很好的簡短語法,我們得到了詞法範圍的this ,所以我們在使用 ES5 時不必像這樣跳過箍:

 var that = this doSomethingAsync().then( function(res) { that.foo(res) })

ES6 中的等價物是:

 doSomethingAsync().then( res => { this.foo(res) })

請注意我是如何省略了一元回調周圍的括號的,因為我可以!

類固醇上的對象文字

ES6 中的對象文字有一些重要的性能增強。 這些天他們可以做各種各樣的事情!

動態屬性名稱

直到寫這篇文章我才真正意識到,從 CoffeeScript 1.9.1 開始,我們現在可以這樣做:

 dynamicProperty = 'foo' obj = {"#{dynamicProperty}": 'bar'}

這比以前需要的這樣的痛苦要少得多:

 dynamicProperty = 'foo' obj = {} obj[dynamicProperty] = 'bar'

ES6 有另一種語法,我認為它非常好,但不是一個巨大的勝利:

 let dynamicProperty = 'foo' let obj = { [dynamicProperty]: 'bar' }

時髦的快捷方式

這實際上取自 CoffeeScript,但直到現在我才知道。 無論如何它非常有用:

 let foo = 'foo' let bar = 'bar' let obj = { foo, bar }

現在obj的內容是{ foo: 'foo', bar: 'bar' } 。 這非常有用,值得記住。

課堂能做的一切我也能做!

對象字面量現在幾乎可以做一個類可以做的所有事情,甚至是:

 let obj = { _foo: 'foo', get foo() { return this._foo }, set foo(str) { this._foo = str }, isFoo() { return this.foo === 'foo' } }

不太清楚你為什麼要開始這樣做,但是嘿,現在你可以了! 你當然不能定義靜態方法……因為那根本沒有意義。

讓你困惑的 for 循環

ES6 for-loop 語法將為有經驗的 CoffeeScripter 引入一些不錯的肌肉記憶錯誤,因為 ES6 的 for-of 轉換為 CoffeeSCript 的 for-in,反之亦然。

ES6

 for (let i of [1, 2, 3]) { console.log(i) } // 1 // 2 // 3

咖啡腳本

for i of [1, 2, 3] console.log(i) # 0 # 1 # 2

我應該切換到 ES6 嗎?

我目前一直在使用 100% CoffeeScript 開發一個相當大的 Node.js 項目,我仍然對它非常滿意並且非常高效。 我想說,在 ES6 中我唯一真正嫉妒的是 getter 和 setter。

而且今天在實踐中使用 ES6 仍然有些痛苦。 如果您能夠使用最新的 Node.js 版本,那麼您幾乎可以獲得所有 ES6 功能,但對於舊版本和瀏覽器來說,情況仍然不那麼樂觀。 是的,你可以使用 Babel,但這當然意味著將 Babel 集成到你的堆棧中。

話雖如此,我可以看到 ES6 在未來一兩年內取得很大進展,我希望在 ES7 中看到更大的成就。

我對 ES6 真正感到滿意的是,“plain old JavaScript”幾乎與 CoffeeScript 一樣友好和強大,開箱即用。 作為一名自由職業者,這對我來說非常棒——在過去,我曾經有點不喜歡在 JavaScript 項目上工作——但是在 ES6 中,一切似乎都變得更加閃亮了。