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