我们在看编写的JS ES6代码时经常会看到许多简写的语法,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。
ES6为一些已有的功能提供了非破坏性更新,这类更新中的大部分我们可以理解为语法糖,称之为语法糖,意味着,这类新语法能做的事情其实用ES5也可以做,只是会稍微复杂一些。本章我们将着重讨论这些语法糖,看完之后,可能你会对一些你很熟悉的ES6新语法有不一样的理解。
JavaScript ES6对象字面量
对象字面量是指以{}形式直接表示的对象,比如下面这样:
var book = {
title: 'Modular ES6',
author: 'Nicolas',
publisher: 'O´Reilly'
}
ES6 为对象字面量的语法带来了一些改进:包括属性/方法的简洁表示,可计算的属性名等等,我们逐一来看:
JavaScript ES6中属性的简洁表示法
你有没有遇到过这种场景,一个我们声明的对象中包含若干属性,其属性值由变量表示,且变量名和属性名一样的。比如下面这样,我们想把一个名为 listeners 的数组赋值给events对象中的listeners属性,用ES5我们会这样做:
var listeners = []
function listen() {}
var events = {
listeners: listeners,
listen: listen
}
ES6则允许我们简写成下面这种形式:
var listeners = []
function listen() {}
var events = { listeners, listen }
怎么样,是不是感觉简洁了许多,使用对象字面量的简洁写法让我们在不影响语义的情况下减少了重复代码。
这是ES6带来的好处之一,它提供了众多更简洁,语义更清晰的语法,让我们的代码的可读性,可维护性大大提升。
可计算的属性名
对象字面量的另一个重要更新是允许你使用可计算的属性名,在ES5中我们也可以给对象添加属性名为变量的属性,一般说来,我们要按下面方法这样做,首先声明一个名为expertise的变量,然后通过person[expertise]这种形式把变量添加为对象person的属性:
var expertise = 'journalism'
var person = {
name: 'Sharon',
age: 27
}
person[expertise] = {
years: 5,
interests: ['international', 'politics', 'internet']
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
ES6 中,对象字面量可以使用计算属性名了,把任何表达式放在中括号中,表达式的运算结果将会是对应的属性名,上面的代码,用ES6可以这样写:
var expertise = 'journalism'
var person = {
name: 'Sharon',
age: 27,
[expertise]: {
years: 5,
interests: ['international', 'politics', 'internet']
}
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
不过需要注意的是,简写属性和计算的属性名不可同时使用。这是因为,简写属性是一种在编译阶段的就会生效的语法糖,而计算的属性名则在运行时才生效。如果你把二者混用,代码会报错。而且二者混用往往还会降低代码的可读性,所以JavaScript在语言层面上限制二者不能混用也是个好事。
var expertise = 'journalism'
var journalism = {
years: 5,
interests: ['international', 'politics', 'internet']
}
var person = {
name: 'Sharon',
age: 27,
[expertise] // 这里会报语法错误
}
遇到以下情景时,可计算的属性名会让我们的代码更简洁:
某个新对象的属性引自另一个对象:
var grocery = {
id: 'bananas',
name: 'Bananas',
units: 6,
price: 10,
currency: 'USD'
}
var groceries = {
[grocery.id]: grocery
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
需构建的对象的属性名来自函数参数。如果使用ES5来处理这种问题,我们需要先声明一个对象字面量,再动态的添加属性,再返回这个对象。下面的例子中,我们创建了一个响应Ajax请求的函数,这个函数的作用在于,请求失败时,返回的对象拥有一个名为error属性及对应的描述,请求成功时,该对象拥有一个名为success属性及对应的描述。
// ES5 写法
function getEnvelope(type, description) {
var envelope = {
data: {}
}
envelope[type] = description
return envelope
}
使用ES6提供的利用计算属性名,更简洁的实现如下:
// ES6 写法
function getEnvelope(type, description) {
return {
data: {},
[type]: description
}
}
对象字面量的属性可以简写,方法其实也是可以的。
JavaScript ES6方法定义
我们先看看传统上如何定义对象方法,下述代码中,我们构建了一个事件发生器,其中的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)
})
}
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
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)
})//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
}
}
ES6中的箭头函数可谓大名鼎鼎了,它有一些特别的优点(关于this),可能你和我一样,使用箭头函数很久了,不过有些细节我之前却一直不了解,比如箭头函数的几种简写形式及使用注意事项。
JavaScript ES6箭头函数
JS中声明的普通函数,一般有函数名,一系列参数和函数体,如下:
function name(parameters) {
// function body
}
普通匿名函数则没有函数名,匿名函数通常会被赋值给一个变量/属性,有时候还会被直接调用:
var example = function (parameters) {
// function body
}
ES6 为我们提供了一种写匿名函数的新方法,即箭头函数。箭头函数不需要使用function关键字,其参数和函数体之间以=>相连接:
var example = (parameters) => {
// function body
}
尽管箭头函数看起来类似于传统的匿名函数,他们却具有根本性的不同:
- 箭头函数不能被直接命名,不过允许它们赋值给一个变量;
- 箭头函数不能用做构造函数,你不能对箭头函数使用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)
//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
> 0
// ES6
var timer = {
seconds: 0,
start() {
setInterval(() => {
this.seconds++
}, 1000)
}
}
timer.start()
setTimeout(function () {
console.log(timer.seconds)
}, 3500)
// <- 3
第一段代码中start方法使用的是常规的匿名函数定义,在调用时this将指向了window,console出的结果为undefined,想要让代码正常工作,我们需要在start方法开头处插入var self = this,然后替换匿名函数函数体中的this为self,第二段代码中,我们使用了箭头函数,就不会发生这种情况了。
还需要说明的是,箭头函数的作用域也不能通过.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对象,这里的arguments其实是其父函数puzzle的。
前面我们提到过,箭头函数