摘要:下例實現了一個數組的迭代器在中,可迭代數據結構比如數組都必須實現一個名為的方法,該方法返回一個該結構元素的迭代器。原話是還可以傳遞返回值。
前記
按照規劃,明年年中,ECMAScript 6(ES6)就要正式發布了。
最近抽空看了Dr. Axel Rauschmayer的幾篇文章和演講PPT,對新特性有了些了解。
趁沒忘,抓緊記錄下,夾雜自己的感受。
計劃分三部分:
新語法
面對對象和模塊化
標準庫擴充
參考了以下文章/PPT:
Use ECMAScript 6 today
Ecmascript 6 Whats next for Javascript
es6 features
ECMAScript 6: arrow functions and method definitions
Callable entities in ECMAScript 6
Iterators and generators in ECMAScript 6
其他文章:
ECMAScript 6新特性印象之二:面對對象和模塊化
總體印象的確是「design by champions」。各種為了代碼書寫效率進行的優化,借鑒了近年各種「新」語言的優秀特性,靈活性大大提升,閱讀難度也提升了……
不過,熟悉Ruby的看了這些會放心不少吧。
新語法1.塊級作用域 關鍵字let, const
function order(x, y) { if (x > y) { let tmp = x; x = y; y = tmp; } console.log(tmp === x); // 引用錯誤:tmp此時未定義 return [x,y]; }
JS終于有了塊級作用域變量。雖然在代碼結構層面沒有太大的作用(以前沒有時也活得很好么,雖然不怎么舒服),但會讓代碼更加準確,更易于閱讀。
今年夏天發布的Swift中也增加了let關鍵字,雖然有些許區別,但目的應該是差不多——提升代碼可讀性。
2.對象字面量的屬性賦值簡寫 property value shorthand
let first = "Bob"; let last = "Dylan"; let singer = { first, last }; console.log(singer.first + " " + singer.last); // Bob Dylan
這對于經常使用對象作為配置屬性參數的苦主來說,算個小小的撫慰了。估計重復添加同一屬性會報錯吧,沒有驗證。
3.方法定義 Method definitions
let obj = { myMethod(arg0, arg1) { ... } };
避免了在對象定義中出現function關鍵字,更加清晰明確地分離出函數的三種用途。
4.賦值解構 Destructuring
let singer = { first: "Bob", last: "Dylan" }; let { first: f, last: l } = singer; // 相當于 f = "Bob", l = "Dylan"
依然是為了方便。以后代碼頭部的「變量定義區域」不會有太多行了。
數組也是可以的,下面這個例子特別棒:
let [all, year, month, day] = /^(ffffdd)-(dd)-(dd)$/.exec("2014-08-31"); let [x, y] = [1, 2, 3]; // x = 1, y = 2
當然也可以這樣,但有些……:
function f([x]) {...} // 參數定義 f(["Blonde on Blonde"]);
下面是幾種錯誤用法(Refutable):
let { a: x, b: y } = {a: 3}; // TypeError let [x, y] = ["a"]; // TypeError
更重要的是,支持默認值,在形式不匹配或目標值undefined時有效:
let { a: x, b: y=5 } = {a: 3, b: undefined }; // x = 3, y = 5 let [x, y="b"] = ["a"]; // x = "a", y = "b"
5.函數的多項返回值 Multiple return values
function findSong(songs, songTitle) { for (let trackNumber = 0; trackNumber < songs.length; trackNumber++) { let song = songs[trackNumber]; if(songTitle ===song.title) { return {song, trackNumber}; } } return {song: undefined, trackNumber: -1} } let songList = ["Tombstone blues", "Don"t think twice", "North country girl"]; let {song, trackNumber} = findSong(songList, "North country girl"); // song = "North country girl", trackNumber = 2;
因為賦值解構,所以也可以這樣:
let {song} = findSong(...); let {trackNumber} = findSong(...); let {trackNumber, song} = findSong(...); // 變量順序不重要
其實就是返回個對象。
但也有個問題,變量名一定要與函數返回對象的屬性名相同,這可以會是一個別扭點。
6.函數參數 - 默認值
function findArtist(name="", genre="") { ... }
沒什么好說的,以后不用再寫var option = option || {}了。
7.函數參數 - 參數打包 Rest parameters
function createArtistProfile(name, ...details) { .. // details是個數組 }
所以,以后也不需要arguments了。不過,看例子只是「1,rest」,不知可不可以「1,2,3,rest」。
8.函數參數 - 數組展開 Spread parameters
Math.max(...[1,11,111]); // 111
算是參數打包的逆操作,以后不用寫[1,2,3].apply(Math.max)這類代碼了。
9.函數參數 - 指名參數 Named parameters
function func(arg0, {opt1, opt2}) { return [opt1, opt2]; } func(0, {opt1: "a", opt2: "b"}) // ["a", "b"]
同樣是通過對象帶來的變化。有個復雜點的例子:
class Entries { // ... selectEntries({ from = 0, to = this.length } = {}) { // Long: { from: from=0, to: to=this.length } // Use `from` and `to` } } let entries = new Entries(); entries.selectEntries({ from: 5, to: 15 }); entries.selectEntries({ from: 5 }); entries.selectEntries({ to: 15 });
指名參數+賦值解構+默認參數,看著反而有點混亂了……自由度大自然帶來閱讀難度的上升,這又是一個權衡點。
10.胖箭頭函數 Arrow functions
let bob = { name: "Bob Dylan", holdConcert: function (songList) { songList.forEach(song => { console.log(this.name + " sang " + song) }); } }
這里形式上借鑒了CoffeeScript里「fat arrow」(ES6對執行和內存上有優化)。Arrow functions主要做了兩件事:
簡化了代碼形式,默認return表達式結果。
自動綁定語義this,即定義函數時的this。如上面例子中,forEach的匿名函數參數中用到的this。
來看幾個例子:
let squares = [ 1, 2, 3 ].map(x => x * x); x => x + this.y // 相當于 function(x) { return x + this.y }.bind(this) // 但胖箭頭在執行效率上會更高
胖箭頭函數與正常函數的區別:
胖箭頭在創建時即綁定this(lexical this);正常函數的this是在執行時動態傳入的(dynamic this)。
胖箭頭沒有內部方法[[Construct]]和屬性原型,所以new (() => {})是會報錯的。
胖箭頭沒有arguments變量。
這樣,以后在定義方法/函數時,就有了清晰的選擇:
定義子程序(subroutine),用胖箭頭,自動獲得語義this。
定義方法(method),用正常函數,動態this。而且可以用方法定義特性簡寫代碼,避免function關鍵字出現。
11.字符串模板 Template strings
templateHandler`Hello ${first} ${last}!`
${first}這樣的結構在Ruby的字符串處理很常見,first是動態替換的部分。templateHandler是替換后的處理函數。
當然也可以不要handler,那就僅僅是模板替換了:
if(x > MAX) { throw new Error(`At most ${MAX} allowed: $(x)!`); }
Template strings支持多行,其間的文本也不會被轉碼:
var str = String.raw`This is a text with multiple lines. Escapes are not interpreted, is not a newline.`;
結合不同的handler,用法多樣,比如正則:
let str = "Bob Dylan - 2009 - Together Through Life"; let albumInfo = str.match(XRegExp.rx` ^(?[^/]+ ) - (? d{4}) - (? [^/]+)$ `); console.log(albumInfo.year); // 2009
12.迭代器 Iterators
稍微熟悉函數式編程(Python,Ruby也可以)的朋友對著這個概念應該都不陌生。ES6參考了Python的設計,迭代器有個next方法,調用會返回:
返回迭代對象的一個元素:{ done: false, value: elem }
如果已到迭代對象的末端:{done: true[, value: retVal] }
上面第二種情況中的條件返回部分是為了遞歸調用生成器而設計的(迭代器其實是生成器的應用之一),具體說明參見這篇文章的對應部分。
下例實現了一個數組的迭代器:
function createArrayIterator(arr) { let index = 0; return { next() { if (index < arr.length) { return { done: false, value: arr[index++] }; else { return { done: true } } } } } let arr = [1,2,3]; let iter = createArrayIterator(arr); console.log(iter.next()); // 1 console.log(iter.next()); // 2
在ES6中,可迭代數據結構(比如數組)都必須實現一個名為Symbol.iterator的方法,該方法返回一個該結構元素的迭代器。注意,Symbol.iterator是一個Symbol,Symbol是ES6新加入的原始值類型。
針對可迭代的數據結構,ES6還引入了一個新的遍歷方法 for-of。再舉個例子,改造下上例中的createArrayIterator:
function createArrayIterator(arr) { let index = 0; return { [Symbol.iterator]() { return this; // 因為本身就是個迭代器 }, next() { ... } } } let arr = [1, 2, 3]; for(x of createArrayIterator(arr)) { // 注意看 console.log(x); }
當然,ES6中的數組本身就是可迭代的,上例僅僅是為了展示而已。
13.生成器 Generators
ES6的生成器同樣借鑒了Python,通過操作符yield來掛起、繼續。
生成器的寫法比較怪異,使用了關鍵字function*:
function* generatorFunction() { yield 1; yield 2; }
生成器返回一個對象,用來控制生成器執行,這個對象是可迭代的:
let genObj = generatorFunction(); genObj.next(); // { done: false, value: 1 } genObj.next(); // { done: false, value: 2 } genObj.next(); // { done: true }
下面這個例子演示了可遞歸調用的生成器,用到了操作符yield*:
function* iterTree(tree) { if (Array.isArray(tree)) { for (let i = 0; i < tree.length; i++) { yield* iterTree(tree[i]); // (*) } } else { yield tree; } }
yield*會交出(yield)全部迭代對象,而不僅僅是一個元素值。原話是「yield* in line (*) yields everything that is yielded by the iterable that is its operand. 」
yield*還可以傳遞返回值。如:
let result1 = yield* step(); // step也是個generator
這個例子不太好,或者說,ES6的這部分實現有點繁瑣,需要更多示例才能理解這個特性。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87626.html
摘要:本文參考了以下文章之前的文章新特性印象之一新語法面對對象關鍵字看上面例子就能明白。定義類的,配合創建新對象。繼承非構造器對象的原型是。錯誤檢查繼承的目標一定要是個對象或者。的構造器是可改寫,但不可枚舉。引入了一個標簽,負責載入模塊。 本文參考了以下文章/PPT: Use ECMAScript 6 today Ecmascript 6 Whats next for Javascrip...
摘要:正大力推進,網景通訊公司即將與他們達成一項協議,讓可以用在瀏覽器上。年月,網景通訊公司和達成協議將被重新命名為,它將會作為瀏覽器中小型客戶端任務的一種腳本語言,同時將會被提升為一種更大的開發富組件的專業工具。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事審校: 為之漫筆鏈接:http://www.zcfy.cc/article/2389原文:https://auth0.com/blog/a-...
摘要:移動端緩存失效是我印象最深的一個之一,為啥呢,因為這個問題導致我加班到很晚。的生命周期是僅在當前會話下有效。引入了一個瀏覽器窗口的概念,是在同源的窗口中始終存在的數據。無bug,不程序:作為程序員的我,不是修bug就是在寫bug的路上。 移動端sessionStorage緩存失效是我印象最深的一個bug之一,為啥呢,因為這個問題導致我加班到很晚。在現在看來就是一個簡單的概念問題。在我剛工作...
摘要:下一步我們將結果輸出到文件。這是我們用編寫的第一個非常簡單的組建。使用將創建的組建導出以便在其它地方能夠正常導入使用。 這是React和ECMAScript6結合使用系列文章的第一篇。 本文出自從零到壹全棧部落 下面是所有系列文章章節的鏈接: React 、 ES6 - 介紹(第一部分) React類、ES7屬性初始化(第二部分) React類,方法綁定(第三部分) ES6中Reac...
摘要:隨后,它出現在公司之后的瀏覽器,以及從微軟從起發布的所有瀏覽器上。標準的第版在年月的大會上被表決接受。第版在年月底大會上被采納。 前言 ??本系列譯文的初衷旨在希望更多人能夠了解關于JS的一些基本概念,遇到原理性的問題時多去翻翻文檔,而不是在社區無休止的重復提出某些在文檔中能夠非常方便快捷就能找到的東西。 ??精力和水平有限,所以暫時只打算嘗試翻譯前面幾章概括性的介紹,同時后面的章節大...
閱讀 2744·2021-11-19 09:40
閱讀 5294·2021-09-27 14:10
閱讀 2099·2021-09-04 16:45
閱讀 1462·2021-07-25 21:37
閱讀 2995·2019-08-30 10:57
閱讀 2981·2019-08-28 17:59
閱讀 1055·2019-08-26 13:46
閱讀 1408·2019-08-26 13:27