關於 ECMAScript 6 和新語法的思考
我和 JavaScript 世界中的許多人一樣,焦急地看著 ECMAScript 以 ECMAScript 6 的形式經歷下一次進化。焦慮是過去的產物,當時我們都在等待 ECMAScript 4 的進化。 ECMAScript 4 倡議似乎更像是將 JavaScript 更改為一種完全不同的語言,即部分 Java、部分 Python 和部分 Ruby。隨之而來的是持不同意見的人群,包括道格拉斯·克羅克福德(Douglas Crockford),他提出了一種更深思熟慮的方法,為訴訟程序帶來了一些理智。結果是 ECMAScript 5,它為該語言引入了幾個新功能,而沒有引入大量新語法。重點似乎是定義 JavaScript 所謂的“神奇”部分,例如只讀屬性和不可枚舉屬性,同時設置前進的路徑以使用嚴格模式刪除“壞部分”。協議是 TC39 將重新召開會議,以解決一些更大的語言問題,這些問題正在 ECMAScript 4 中得到解決,並在 ECMAScript 5 中得到解決。這個過程開始創建代號為“Harmony”的語言的下一個版本。
現在,我們在 ECMAScript 6 的開發上已經走得更遠了,所以現在是停下來看看發生了什麼的好時機。顯然,任何語言的發展都集中在添加新功能上。 ECMAScript 5 中添加了新功能,我完全預計 ECMAScript 6 會繼續這樣做。我沒想到的是新功能最終會如何與新語法綁定。
好的新語法
我與人們就各種 ECMAScript 6 特性進行了多次對話,許多人錯誤地認為我反對使用新語法。事實並非如此。當它做兩件事時,我喜歡新語法:簡化已經存在的模式並在給定語法的其餘部分的情況下具有邏輯意義。例如,我認為添加 let
用於創建塊範圍的變量和 const
用於定義常量是有意義的。語法與使用 var
相同 ,所以我很容易在我的代碼中進行必要的調整:
var SOMETHING = "boo!";
const SOMETHING = "boo!";
let SOMETHING = "boo!";
使用熟悉語法的新關鍵字的認知開銷非常低,因此開發人員不太可能對其用法感到困惑。
同樣,添加 for-of
loop 是 Array.prototype.forEach()
周圍的一些語法糖 , 加上對類數組項的一些兼容性(使其成為 Firefox 通用 Array.forEach()
的語法糖 )。因此您可以輕鬆更改此代碼:
var values = [1, 2, 3, 4, 5, 6];
values.forEach(function(value) {
console.log(value);
});
進入這個:
var values = [1, 2, 3, 4, 5, 6];
for (let value of values) {
console.log(value);
}
這對我來說完全有意義。語法與已經存在的 for
非常相似 和 for-in
循環並模仿 Array.prototype.forEach()
已有的內容 .我看看這段代碼,它看起來仍然像 JavaScript,這讓我很高興。即使我選擇不使用新語法,我仍然可以完成同樣的事情。
新語法錯誤
ECMAScript 6 的特性之一,受到所謂的“胖箭頭”函數的廣泛關注 1 .這似乎是為了解決幾個問題:
this
綁定 – 希望更容易指定this
的值 在一個函數內。這是Function.prototype.bind()
的問題 解決了。- 避免輸入“函數” – 出於某種原因,人們似乎討厭輸入“功能”這個詞。 Brendan Eich 本人曾表示,他後悔使用這麼長的詞。我從來沒有真正遇到過問題,也沒有理解人們對不得不輸入這些字符的挫敗感。
- 避免輸入括號、大括號 – 再一次,語法似乎是個問題。再一次,我就是不明白。
所以本質上是這樣的:
function getName() {
return this.name;
}
var getWindowName = getName.bind(window);
變成這樣:
var getWindowName = () => this.name;
還有這個:
function getName(myName) {
return this.name + myName;
}
var getWindowName = getName.bind(window);
變成這樣:
var getWindowName = myName => this.name + myName;
我知道我可能獨自一人,但我不認為語法很清楚。如果函數沒有參數,則需要提供括號;此外,如果有多個參數,則需要括號。如果只有一個參數,那麼你不需要括號。跟我到現在?
如果要從這些函數之一返回對象字面量,則必須將對象字面量和括號括起來:
let key_maker = val => ({key: val});
那麼如果你想在函數體中做不止一件事,你需要將它包裹在大括號中並使用 return
就像在常規函數中一樣:
let sumIt = (val1, val2) => {
var sum = val1 + val2;
return sum;
};
不要誤以為這些函數的行為與所有其他函數一樣。使用胖箭頭語法聲明的函數和以更傳統方式聲明的函數之間有幾個重要區別:
- 如前所述,
this
的值 是靜態的。它總是取this
的值 用於封閉函數或全局範圍。 - 你不能使用
new
使用粗箭頭函數會引發錯誤。 - 胖箭頭函數沒有
prototype
財產。
因此,箭頭函數不僅試圖解決一堆問題,它們還引入了一堆從語法中看不到的副作用。這是我不喜歡的新語法類型。如果您認為這只是編寫函數的一種簡寫方式,那麼箭頭函數會發生很多意想不到的事情。
更重要的是,我不知道如何大聲讀出來。我一直喜歡 JavaScript 的一件事是它說明了它的作用,因此我實際上可以大聲朗讀代碼並且它是有意義的。我不知道如何發音那個箭頭函數。 “讓變量等於執行某些語句的一組參數?”它對我不起作用。在某些方面,當您嘗試用一個解決方案解決多個問題時,您最終會遇到這種問題。這種語法有很多規則需要記住,還有很多副作用需要考慮。
只是為了爭論,如果有人問我建議用什麼樣的新語法來加糖 Function.prototype.bind()
,我會選擇這樣的東西:
// My own attempt at sugaring Function.prototype.bind() - not ES6
function<window> getName() {
return this.name;
}
這種語法對我來說看起來很熟悉,但實際上是新的。我會將其解讀為“在窗口範圍內定義一個名為 getName 的函數”。這個想法是 this
最終總是等於 window
.誠然,箭頭函數只解決了箭頭函數試圖解決的問題之一,但至少它說明了它的作用。
醜陋的新語法
ECMAScript 6 中的其他特性讓我覺得 JavaScript 正在成為一種 ASCII 藝術語言。出於某種原因,規範沒有使用現有語法添加新功能,而是僅使用新語法添加新功能。最讓我困惑的是,這些功能是其他語言已經以某種形式存在的功能。
恰當的例子:準(又名准字面量) 2 . Quasis 似乎是 JavaScript 中許多不同問題的解決方案。據我所知,quasis 應該可以解決所有這些問題:
- 字符串格式 – JavaScript 已經錯過了很長時間。 C# 和 Java 等語言有一個稱為
String.format()
的方法 允許在字符串中進行簡單的符號替換。老實說,在 JavaScript 中實現它會讓我非常高興(Crockford 實際上已經提出了一些類似的東西 3 )。 - 多行字符串 – 出於某種原因,人們覺得需要一種標準的方式來處理多行字符串,而不是在換行符之前使用反斜杠實現的方式。
- HTML 轉義 – 這也是 JavaScript 長期以來一直缺少的東西。雖然它已經提供了 URL 轉義很長一段時間,但 HTML 轉義明顯缺失。
Quasis 使用反引號(`
) 表示需要變量替換的代碼段。在反引號內,包含在 ${...}
中的任何內容 在當前上下文中將被解釋為 JavaScript。基本語法如下:
someFunc`Some string ${value}`;
這個想法是 someFunc
是解釋包含在反引號中的值的函數(準處理程序)的名稱。提案中有幾個用例,例如創建一個 safehtml
用於進行 HTML 轉義和 msg
的準處理程序 用於執行本地化替換的準處理程序。 ${value}
被解釋為名為 value
的變量的值 .您還可以在反引號中包含多行:
someFunc`Some string ${value}.
And another line.`;
我不打算深入討論 quasis 的所有細節,因為你應該看看 Axel Rauschmayer 的文章 4 .如果您閱讀他的帖子,您會發現這是對我之前提到的已經解決的問題的一個相當複雜的解決方案。更重要的是,它在我看來甚至不像 JavaScript。除了多行字符串,這些問題都可以使用常規的 JavaScript 語法來解決。再一次,如果由我來決定,我會這樣解決它們:
// My take at string formatting - not in ES6
var result = String.format("Hi %s, nice day we're having.", name);
// My take at HTML escaping - not in ES6
var result = String.escapeHtml("Does it cost < $5?");</code>
在這些情況下,當水槍就足夠時,似乎正在使用火箭筒。添加格式化字符串和轉義 HTML 的功能對於 JavaScript 的未來當然很重要,我只是不明白為什麼必須有一種新的語法來解決這些問題。在 ECMAScript 6 的所有內容中,quasis 是我希望以可怕而痛苦的方式死去的特性。
結論
誠然,我是一個 JavaScript 純粹主義者,但我願意接受新的語法,只要它有意義。我更希望使用現有語法添加新功能,然後為那些選擇使用它的人添加語法糖。僅使用新語法提供新功能,就像 quasis 的情況一樣,對我來說沒有意義,尤其是當問題既定義明確又以前使用其他語言使用更簡單的解決方案解決時。此外,僅對新功能使用新語法意味著無法進行特徵檢測。
似乎在某些情況下,TC 39 最終為某個問題創建了最複雜的解決方案,或者嘗試同時解決一堆問題,從而產生了箭頭函數和擬態等科學怪人特徵。我相信意圖總是好的,那就是避免其他語言遇到的問題。然而,結果似乎使 JavaScript 更加複雜,語法更加陌生。我不希望 JavaScript 成為 Python 或 Ruby 或 JavaScript 以外的任何其他東西。
參考
- Brendan Eich 的箭頭函數語法
- 準字面量
- Douglas Crockford 的 String.prototype.format()
- 准文字:Axel Rauschmayer 博士在 ECMAScript.next 中嵌入的 DSL