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