1. 程式人生 > >ES6 物件簡寫 計算屬性 箭頭函式 物件解構

ES6 物件簡寫 計算屬性 箭頭函式 物件解構

        //物件字面量
        /*
            以{}形式直接表示的物件
        */
       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語義更清晰
但是如果你需要提取物件中的子物件,結構就更加方便
*/