[译]十个极好的ES6特性

原文:Top 10 ES6 features by example

作者:Łukasz Kyć

尽管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辅助函数

出现了新的很酷很有用的数组辅助函数。试想下你曾经多少次实现这些逻辑:筛选,检查是否一些或者全部元素都符合给定的条件,或者元素转换?可能非常频繁。现在有很好的语言特性来帮你做这些工作。下面是在我看来最有价值的函数:

forEach
对数组的每个元素执行给定的函数,数组元素作为参数传递。

var colors = ['red', 'green', 'blue']

function print(val) {
  console.log(val)
}

colors.forEach(print)

结果

red 
green 
blue

map
创建一个有同样数量元素的新数组,但是输出的元素由提供的函数创建。它只对每个数组元素进行转换。

var colors = ['red', 'green', 'blue']

function capitalize(val) {
    return val.toUpperCase()
}

var capitalizedColors = colors.map(capitalize)

console.log(capitalizedColors)

结果

["RED","GREEN","BLUE"] 

filter
创建一个原来数组的子集。结果包括那些通过指定函数测试的元素,函数返回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] 

find

返回第一个通过给定函数测试的元素,函数返回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 

every

检查是否所有的数组元素都满足给定的测试函数,函数返回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 

some

检查是否有一些元素满足给出的测试函数,函数返回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
对累加器和数组中的每个元素(从左到右)依次执行一个函数(第一个参数),把数组减少为一个值。累加器的初始值是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操作符

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"] 

Rest
想要把函数第一个参数绑定为变量,而其他的的变量作为数组传递?现在你可以很简单的实现。

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

感谢Krzysztof Jelski

Comments
Write a Comment