//对象字面量
        /*
            以{}形式直接表示的对象
        */
       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语义更清晰
但是如果你需要提取对象中的子对象,结构就更加方便
*/