ES6 物件簡寫 計算屬性 箭頭函式 物件解構
阿新 • • 發佈:2019-02-08
//物件字面量 /* 以{}形式直接表示的物件 */ var book = { title:"Modular ES6", author:"Nicolas", publisher:"O`Reilly" } /* 屬性的簡潔表示法 */ //ago var listeners = [] function listen(){ } var events = { listeners:listeners, listen:listen } /* ES6簡寫 減少程式碼重複讀,增加可讀性 */ var listeners = [] function listen(){ } var events = {listeners , listen} /* 可計算的屬性名 */ //原寫法 var expertise = 'journalism' var person = { name:"Sharon", age:27 } person[expertise] = { years:5, interests:['international' , 'politics' , 'internet'] } /* ES6寫法 物件字面量可以使用計算屬性名,把任何表示式放在中括號裡, 表示式的運算結果將會是對應的屬性名 */ var expertise = 'journalism' var person = { name:"Sharon", age:27, [expertise]:{ years:5, interests:['international','politics','internet'] } } /* 注意: 簡寫屬性和計算屬性名不可以同時試用。 簡寫屬性是一種編譯階段生效的語法糖 計算的屬性名在執行時才生效 兩者混用會報錯,降低可讀性 下面是錯誤寫法: var expertise = 'journalism' var journalism = { years: 5, interests: ['international', 'politics', 'internet'] } var person = { name: 'Sharon', age: 27, [expertise] // 這裡會報語法錯誤 } */ /* 下面這種情況,可計算的屬性名可以讓程式碼更簡潔 eg:某個新物件的屬性引自另一個物件: */ var grocery = { id:'bananas', name:'Bananas', units:6, price:10, currency:'USD' } var groceries = { [grocery.id]:grocery } /* 需要構建的物件的屬性名來自函式引數, 如果在es5處理,需要先宣告一個物件字面量 再動態的新增屬性,再返回這個物件 */ //es5 function getEnvelope(type,description){ var envelope = { data:{} } envelope[type] = description return envelope } //es6提供的利用計算屬性名,簡潔寫法如下: function getEnvelope(type,description){ return{ data:{}, [type]:description } } /* 方法定義 傳統定義物件方法的方式,以下程式碼構建了一個事件發生器 其中的on方法用以註冊時間,emit方法用以執行事件 */ var emitter = { events:{}, on:function (type,fn){ if(this.events[type] === undefined){ this.events[type] = [] } this.events[type].push(fn) }, emit:function(type,event){ if(this.events[type] === undefined){ return } this.events[type].forEach(function(fn){ fn(event) }) } } /* ES6的物件字面量方法簡寫允許我們省略function關鍵字 以及之後的冒號 */ var emitter = { events:{}, on(type,fn){ if(this.events[type] === undefined){ this.events[type] = [] } this.events[type].push(fn) }, emit(type,event){ if(this.events[type] === undefined){ return } this.events[type].forEach(function(fn){ fn(event) }) } } /* 箭頭函式 不需function關鍵字,引數和函式體之間用=>相連 與匿名函式的不同點: 箭頭函式不能被直接命名,不過允許他們賦值給一個變數 箭頭函式不能用作建構函式,你不能對箭頭函式試用new關鍵字 箭頭函式沒有prototype屬性 箭頭函式綁定了詞法作用域,不會修改this的指向 下面是箭頭函式的最大特點: 我們在箭頭函式的函式體內試用this,arguments,super 等都指向包含箭頭函式的上下文,箭頭函式本身不產生新 的上下文,下述程式碼中,我們建立了一個名為timer的對 象,他的屬性seconds用以計時,方法start用以開始計 時,若我們在若干秒後呼叫start方法,將打印出當前的 seconds值 */ //ES5 var timer = { seconds:0, start(){ setInterval(function(){ this.seconds++ },1000) } } timer.start() setTimeout(function(){ console.log(timer.seconds) },3500) /* >0 解析: start中的this指向window console輸出undefined 所以呼叫的時候3.5秒後輸出的seconds還是0 如需要改寫可以向start(){}中新增 var that = this ,將下面的this改為that 即可輸出3, ES6不會出現這種指向性的情況: */ var tiemr = { seconds:0, start(){ setInterval(()=>{ this.seconds++ }) } } timer.start() setTimeout(function(){ console.log(timer.seconds) },3500) /* 由於不存在指向性問題,所以輸出正確值3 箭頭函式的作用域不能通過.call,.apply,.bind等語法 改變,這使得箭頭函式的上下文永久不變, 再來幾個例子: */ function puzzle(){ return function(){ console.log(arguments) } } puzzle('a','b','c')(1,2,3) //1,2,3 因為對於匿名函式而言,arguments指向本身 function puzzle(){ return ()=>{ console.log(arguments) } } puzzle('a','b','c')(1,2,3) //a,b,c 箭頭函式的特殊性決定其本身沒有arguments物件,這裡的是其父函式puzzle的 /* 簡寫的箭頭函式 */ var example = (parameters) => { //函式體 } /* 簡寫1 當只有一個引數的時候,我們可以省略箭頭函式引數兩側的括號 */ var doublue = value => { return value * 2 } /* 簡寫2 對只有單行表示式並且該表示式的值為返回值的箭頭函式, {}可以省略,return可以省略 */ var double = (value) => value*2 /* 簡寫3 合併使用 */ var double = value => value*2 /* 簡寫箭頭函式帶來的問題 當你簡寫箭頭函式返回值為一個物件的時候,你需要用 小括號來擴起你想返回的物件,否則瀏覽器會把物件的 {}解析為箭頭函式函式體的開始結束標記 下面是正確的簡寫形式 */ var objectFactory = () => ({modular:"es6"}) /* 下面是錯誤的形式 箭頭函式會把本想返回的物件的花括號解析為函式體 number被解析為label,value解釋為沒有做任何事 情表示式,而且沒有顯式的試用return,返回值預設 是undefined */ [1,2,3].map(value => {number:value}) /*[undefined,undefined,undefined] 當我們返回的物件字面量不止一個屬性的時候, 瀏覽器編譯器不能正確解析第二個屬性,這時 會丟擲語法錯誤 */ [1,2,3].map(value=>{number:value,verfied:true}) //解決 把返回的物件字面量博鰲國在小括號中,幫助瀏覽器正確解析 [1,2,3].map(value=>({number:value,verfied:true})) /* [{ number: 1, verified: true }, { number: 2, verified: true }, { number: 3, verified: true }] */ /* 該何時試用箭頭函式 箭頭函式並非適用於所有的情況,比如說,對於一個行數 很多的複雜函式,試用=>代替function關鍵字帶來的簡潔 性並不明顯,箭頭函式不能直接命名,但是可以通過賦值給 變數的形式實現間接命名,如下程式碼中,我們把箭頭函式賦值 給變數throwError,當函式被呼叫時,會丟擲錯誤,這個時候 可以追溯到是箭頭函式throwError報的錯 */ var throwError = message => { throw new Error(message) } throwError('this is a warning') /* error:this is a warning 如果你想完全控制你函式中的this, 使用箭頭函式是簡潔高效的,採用 函式式變成尤其如此 */ [1,2,3,4] .map(value => value * 2) .filter(value => value >2) .forEach(value => console.log(value)) /* 4 6 8 */ /* 解構賦值 ES6提供的最靈活和富於表現性的新特徵最莫過於解構, 某種程度上解構可以看做是變數賦值的語法糖,可以 應用於物件,陣列深知函式的引數。 1.物件解構 為了更好的描述物件解構如何使用,我們先構建下面 這樣一個物件: */ //描述Bruce Wayne的物件 var character = { name:"Bruce", pseudonym:"Batman", metadata:{ age:34, gender:'male' }, batarang:['gas pellet' , 'bat-mobile control' , 'bat-cuffs'] } /* 假如現在有一個名為pseudonym的變數,我們 想讓其變數值指向character.pseudonym, 使用es5: */ var pseudonym = character.pseudonym //ES6致力於讓我們的程式碼更簡潔,通過ES6我們可以用這段程式碼實現同樣功能: var { pseudonym } = character //如同你可以使用var加逗號在一行中同時宣告多個變數,解構的花括號內也可以做: var { pseudonym , name } = character //還可以混用解構和常規的自定義變數,這也是解構語法靈活性的表現之一 var { pseudonym } = character , two = 2 //解構允許我們使用別名,如果我們想把character.pesudontm賦值給變數alias,可以這樣 var { pseudonym : alias } = character //對於多層解構,也可以賦予別名,可以通過非常簡潔的方法修改子屬性名稱: var { metadata:{ gender:characterGender } } = character //ES5中,呼叫未曾生宣告的值,你會得到undefined console.log(character.boots) console.log(character['boots']) //都是undefined,使用解構,情況也是類似的 var { boots } = character console.log(boots) //對於多層結構,boots不存在與character中,這時程式會丟擲異常,好比呼叫undefined和null var { boots:{size} } = character var { missing } = null //解構其實就是一種語法糖,下面這段程式碼幫助理解 var nothing = null var missing = nothing.missing //結構可以新增預設值,如果右側不存在對應的值,預設值生效,預設值可以是數值,字串,函式,物件,也可以是某一個存在的變數: var { boots = { size : 10 } } = character console.log(boots) //對於多層結構,同樣可以使用預設值 var { metadata:{ enemy = 'Satan' } } = character console.log(enemy) //預設值和別名也可以一起使用,不過要注意別名要放在前面 var { boots:footwear = {size:10} } = character //物件解構支援計算屬性名,這個時候必須新增別名,這是因為計算屬性名允許任何型別表示式 //不新增別名瀏覽器解析的時候會出問題 var {['boo' + 'ts']:characterBoots} = character /*不是在任何情況下都應該使用結構,語句characterBoots = character[type] 看起來比{[type]:charaterBoots} = character語義更清晰 但是如果你需要提取物件中的子物件,結構就更加方便 */