十个极好的ES6特性
尽管ES6规范不是什么新鲜的东西了,但是我想很多开发者仍然对它不是很熟悉。主要原因可能是浏览器对它的支持晚于规范的发布。现在,规范已经发布两年了,很多现代浏览器都能很好的支持ES6。即使你(或者你的客户)不使用最新版本的浏览器,你也可以使用编译器(比如Babel)在应用的构建过程中把ES6转换成ES5。也就是说,现在是时候迈开步子,学习ES6了。
在这篇文章中,我将尝试简明扼要的介绍一些常用的特性。教程结束后,你将会掌握一些基础的技能,并把它们应用到具体的项目中。不要把它当做指南或者文档。我的目的是鼓励你深入的了解和熟悉ES6。
1. const和let关键字
const用来定义常量(终于有了!)let用来定义变量。很棒,但是javascript中不是已经有变量了么?的确如此,但是通过var定义的变量具有函数作用域并且会被提升到顶部。这就意味着一个变量可以在他被声明前使用。让变量和常量具有块级作用域(被{}包围)并且不能在声明之前使用。
function f() {
var x = 1
let y = 2
const z = 3
{
var x = 100
let y = 200
const z = 300
console.log('x in block scope is', x)
console.log('y in block scope is', y)
console.log('z in block scope is', z)
}
console.log('x outside of block scope is', x)
console.log('y outside of block scope is', y)
console.log('z outside of block scope is', z)
}
f()
结果
x in block scope is 100
y in block scope is 200
z in block scope is 300
x outside of block scope is 100
y outside of block scope is 2
z outside of block scope is 3
2.Array辅助函数
出现了新的很酷很有用的数组辅助函数。试想下你曾经多少次实现这些逻辑:筛选,检查是否一些或者全部元素都符合给定的条件,或者元素转换?可能非常频繁。现在有很好的语言特性来帮你做这些工作。下面是在我看来最有价值的函数:
对数组的每个元素执行给定的函数,数组元素作为参数传递。
var colors = ['red', 'green', 'blue']
function print(val) {
console.log(val)
}
colors.forEach(print)
结果
red
green
blue
创建一个有同样数量元素的新数组,但是输出的元素由提供的函数创建。它只对每个数组元素进行转换。
var colors = ['red', 'green', 'blue']
function capitalize(val) {
return val.toUpperCase()
}
var capitalizedColors = colors.map(capitalize)
console.log(capitalizedColors)
结果
["RED","GREEN","BLUE"]
创建一个原来数组的子集。结果包括那些通过指定函数测试的元素,函数返回true或者false。
var values = [1, 60, 34, 30, 20, 5]
function lessThan20(val) {
return val < 20
}
var valuesLessThan20 = values.filter(lessThan20)
console.log(valuesLessThan20)
[1,5]
返回第一个通过给定函数测试的元素,函数返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var firstTeenager = people.find(teenager)
console.log('First found teenager:', firstTeenager.name)
结果
First found teenager: Ann
检查是否所有的数组元素都满足给定的测试函数,函数返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var everyoneIsTeenager = people.every(teenager)
console.log('Everyone is teenager: ', everyoneIsTeenager)
结果
Everyone is teenager: false
检查是否有一些元素满足给出的测试函数,函数返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var thereAreTeenagers = people.some(teenager)
console.log('There are teenagers:', thereAreTeenagers)
结果
There are teenagers: true
对累加器和数组中的每个元素(从左到右)依次执行一个函数(第一个参数),把数组减少为一个值。累加器的初始值是reduce函数的第二个参数。
var array = [1, 2, 3, 4]
function sum(acc, value) {
return acc + value
}
function product(acc, value) {
return acc * value
}
var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)
console.log('Sum of', array, 'is', sumOfArrayElements)
console.log('Product of', array, 'is', productOfArrayElements)
结果
Sum of [1,2,3,4] is 10
Product of [1,2,3,4] is 24
3.箭头函数
非常简单的函数(比如上面提到的sum或product)也需要写很多代码。还有别的解决方法么?当然,试一试箭头函数吧!
var array = [1, 2, 3, 4]
const sum = (acc, value) => acc + value
const product = (acc, value) => acc * value
var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)
箭头函数可以写在同一行。它真的简化了代码。
var array = [1, 2, 3, 4]
var sumOfArrayElements = array.reduce((acc, value) => acc + value, 0)
var productOfArrayElements = array.reduce((acc, value) => acc * value, 1)
箭头函数也可以更加复杂,有很多行代码。
ar array = [1, 2, 3, 4]
const sum = (acc, value) => {
const result = acc + value
console.log(acc, ' plus ', value, ' is ', result)
return result
}
var sumOfArrayElements = array.reduce(sum, 0)
4.类
哪个Java开发者转而做JS项目时候不会怀念类呢?相比较写原型继承的代码,谁不喜欢像Java语言里那样直截了当的继承呢?尽管一些JS开发者有所抱怨,ES6中已经引入了类。它们并没有改变继承的思想,只是原型链继承的语法糖。
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
toString() {
return '[X=' + this.x + ', Y=' + this.y + ']'
}
}
class ColorPoint extends Point {
static default() {
return new ColorPoint(0, 0, 'black')
}
constructor(x, y, color) {
super(x, y)
this.color = color
}
toString() {
return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']'
}
}
console.log('The first point is ' + new Point(2, 10))
console.log('The second point is ' + new ColorPoint(2, 10, 'green'))
console.log('The default color point is ' + ColorPoint.default())
结果
The first point is [X=2, Y=10]
The second point is [X=2, Y=10, color=green]
The default color point is [X=0, Y=0, color=black]
5.加强的对象字面量
对象字面量被加强,现在我们可以更加容易的:
+ 用变量定义同名的字段
+ 定义函数
+ 定义动态(计算得到的)属性
const color = 'red'
const point = {
x: 5,
y: 10,
color,
toString() {
return 'X=' + this.x + ', Y=' + this.y + ', color=' + this.color
},
}
console.log('The point is ' + point)
console.log('The dynamic property is ' + point.prop_42)
结果
The point is X=5, Y=10, color=red
The dynamic property is 42
6.模板字符串
我相信只有一小部分人喜欢写大量的字符串和变量连结,但是所有人都讨厌阅读它。幸运的是,ES6引入了非常好用的字符串模板以及变量占位符。
function hello(firstName, lastName) {
return `Good morning ${firstName} ${lastName}!
How are you?`
}
console.log(hello('Jan', 'Kowalski'))
结果
Good morning Jan Kowalski!
How are you?
请注意,我们可以写成多行文本。
重点:使用倒引号代替引号来包裹文本。
7.函数默认参数
想提供所有可能的函数参数么?使用默认值。
function sort(arr = [], direction = 'ascending') {
console.log('I\'m going to sort the array', arr, direction)
}
sort([1, 2, 3])
sort([1, 2, 3], 'descending')
结果
I'm going to sort the array [1,2,3] ascending
I'm going to sort the array [1,2,3] descending
8.rest和spread操作符
它将数组或对象提取成单个元素。
举个栗子 — 数组的浅拷贝:
var array = ['red', 'blue', 'green']
var copyOfArray = [...array]
console.log('Copy of', array, 'is', copyOfArray)
console.log('Are', array, 'and', copyOfArray, 'same?', array === copyOfArray)
结果
Copy of ["red","blue","green"] is ["red","blue","green"]
Are ["red","blue","green"] and ["red","blue","green"] same? false
栗子 — 合并数组:
var defaultColors = ['red', 'blue', 'green']
var userDefinedColors = ['yellow', 'orange']
var mergedColors = [...defaultColors, ...userDefinedColors]
console.log('Merged colors', mergedColors)
结果
Merged colors ["red","blue","green","yellow","orange"]
想要把函数第一个参数绑定为变量,而其他的的变量作为数组传递?现在你可以很简单的实现。
function printColors(first, second, third, ...others) {
console.log('Top three colors are ' + first + ', ' + second + ' and ' + third + '. Others are: ' + others)
}
printColors('yellow', 'blue', 'orange', 'white', 'black')
结果
Top three colors are yellow, blue and orange. Others are: white,black
9.解构赋值
从数组中提取需要的元素并分配给变量。
function printFirstAndSecondElement([first, second]) {
console.log('First element is ' + first + ', second is ' + second)
}
function printSecondAndFourthElement([, second, , fourth]) {
console.log('Second element is ' + second + ', fourth is ' + fourth)
}
var array = [1, 2, 3, 4, 5]
printFirstAndSecondElement(array)
printSecondAndFourthElement(array)
结果
First element is 1, second is 2
Second element is 2, fourth is 4
从对象中提取需要的属性并分给和属性同名的变量。
function printBasicInfo({firstName, secondName, profession}) {
console.log(firstName + ' ' + secondName + ' - ' + profession)
}
var person = {
firstName: 'John',
secondName: 'Smith',
age: 33,
children: 3,
profession: 'teacher'
}
printBasicInfo(person)
结果
John Smith - teacher
10. Promises
Promise承诺你获得延迟或长期运行任务的结果。Promise有两个通道:第一个是结果,第二个是可能的错误。要获取结果,提供回调函数作为‘then’函数的参数。要处理错误,提供回调函数作为‘catch’函数的参数。
请注意下面例子每次执行的结果可能不一致,因为调用了随机函数。
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const result = Math.random();
result > 0.5 ? resolve(result) : reject('Oppps....I cannot calculate')
}, 1)
});
}
for (let i=0; i<10; i++) {
asyncFunc()
.then(result => console.log('Result is: ' + result))
.catch(result => console.log('Error: ' + result))
}
结果
Result is: 0.7930997430022211
Error: Oppps....I cannot calculate
Result is: 0.6412258210597288
Result is: 0.7890325910244533
Error: Oppps....I cannot calculate
Error: Oppps....I cannot calculate
Result is: 0.8619834683310168
Error: Oppps....I cannot calculate
Error: Oppps....I cannot calculate
Result is: 0.8258410427354488
总结
希望你喜欢这篇文章。如果你想做一些练习,可以使用ES6 Console - try JavaScript compilers。如果你需要更多的信息,可以访问:
+ GitHub - lukehoban/es6features: Overview of ECMAScript 6 features
+ Exploring ES6