JavaScriptES6为JavaScript语言添加了一系列新特性,其中一些特性更具有开拓性,而且比其他特性更适用。像ES6类例如,虽然新颖,但在现有的JavaScript类创建方法的基础上添加了语法糖,而生成器等功能虽然非常强大,但却保留给更专门的任务。

从过去12个月从事各种JavaScript相关项目来看,我发现ES6的五个最重要的特性是必不可少的,因为它们真正简化了JavaScript中常见任务的完成方式。你的前五名可能与我的不同,如果他们是,我鼓励你分享在评论部分的结尾。

开始吧!

  1. 箭头函数

  2. 承诺

  3. 异步函数

  4. 解构

  5. 默认和REST参数

1)JavaScript Arrow函数

在ES6JavaScript中,我最喜欢的一个新增功能不是一个新特性,而是一个令人耳目一新的新语法集,每当我使用它时,它都会让我面带微笑。我说的是Arrow函数,它提供了一种非常优雅和极简的方法来定义JavaScript中的匿名函数。

简而言之,Arrow函数会删除“function“关键字,并使用箭头(=>)将函数的函数体中的参数部分。匿名职能:

1
(x, y) => x * y;

这相当于:

1
2
3
function (x, y){
     return x * y;
}

或:

1
2
3
4
(x, y) => {
     var factor = 5;
     var growth = (x-y) * factor;
}

与以下内容相同:

1
2
3
4
function (x, y){
     var factor = 5;
     var growth = (x-y) * factor;
}

使用传统的匿名函数时,箭头函数还移除一个关键错误源,即this“函数中的对象。使用Arrow函数,“this“在词汇上是绑定的,这是只是一种奇特的表达方式,它的值被绑定到父范围,并且永不改变。如果 箭函数在自定义对象中定义为“countup的价值this“指向”countup“-没有任何猜测。例如:

1
2
3
4
5
6
7
8
9
10
11
var countup = {
     counter: 15,
      
     start: function (){
         window.addEventListener( 'click' , () => {
             alert( this .counter) // correctly alerts 15 due to lexical binding of this
         })
     }
};
  
countup.start();

将其与传统的匿名函数进行比较,其中“this“更改取决于在其中定义的上下文。试图引用的结果this.counter在上述情况下将返回undefined这种行为可能会使许多人不熟悉动态绑定的复杂性。对于Arrow函数,“this“总是可以预测和容易推断的。

有关“箭上的瘦身”功能,请参阅“JavaScriptArrow函数概述".

2)JavaScript承诺

JavaScriptES6承诺简化异步任务的处理方式,这是一个在大多数现代Web应用程序中发挥作用的任务。JavaScript承诺使用一种中心的、直观的机制来跟踪和响应异步事件,而不是依赖回调函数(由jQuery等JavaScript框架推广)。它不仅使调试异步代码变得更加容易,而且编写异步代码也是一种乐趣。

所有JavaScript承诺的生存和死亡Promise()构造者:

1
2
3
4
5
const mypromise = new Promise( function (resolve, reject){
  // asynchronous code to run here
  // call resolve() to indicate task successfully completed
  // call reject() to indicate task has failed
})

使用resolve()reject()方法在内部,当承诺被履行和拒绝时,我们可以分别向承诺对象发出信号。这,这个,那,那个then()catch()然后可以调用方法来处理完全填充或被拒绝的承诺的后果。

我一直使用以下承诺的变体注入XMLHttpRequest函数,依次检索外部文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getasync(url) {
     return new Promise((resolve, reject) => {
         const xhr = new XMLHttpRequest()
         xhr.open( "GET" , url)
         xhr.onload = () => resolve(xhr.responseText)
         xhr.onerror = () => reject(xhr.statusText)
         xhr.send()
     })
}
 
getasync( 'test.txt' ).then((msg) => {
     console.log(msg) // echos contents of text.txt
     return getasync( 'test2.txt' )
}).then((msg) => {
     console.log(msg) // echos contents of text2.txt
     return getasync( 'test3.txt' )
}).then((msg) => {
     console.log(msg) // echos contents of text3.txt
})

要掌握JavaScript承诺的关键方面,例如链接承诺和并行执行承诺,请阅读“承诺初学者指南".

3)JavaScript异步函数

除了JavaScript承诺之外,异步函数还进一步重写了传统异步代码的构造,使其更加可读性更强,更易于理解。每当我向客户显示代码时async 函数交织在一起,第一反应总是令人惊讶,接着是强烈的好奇心,以了解它是如何工作的。

异步函数由两部分组成:

1)以前缀为前缀的正则函数async功能

1
2
3
4
async function fetchdata(url){
     // Do something
     // Always returns a promise
     }

2)使用await关键字在主异步函数中异步函数调用之前。

一个例子胜过千言万语。下面是上面基于承诺的示例的重写,以供使用异步函数相反:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function getasync(url) { // same as original function
     return new Promise((resolve, reject) => {
         const xhr = new XMLHttpRequest()
         xhr.open( "GET" , url)
         xhr.onload = () => resolve(xhr.responseText)
         xhr.onerror = () => reject(xhr.statusText)
         xhr.send()
     })
}
 
async function fetchdata(){ // main Async function
     var text1 = await getasync( 'test.txt' )
     console.log(text1)
     var text2 = await getasync( 'test2.txt' )
     console.log(text2)
     var text3 = await getasync( 'test3.txt' )
     console.log(text3)
     return "Finished"
}
 
fetchdata().then((msg) =>{
     console.log(msg) // logs "finished"
})

上面的示例在运行时按顺序回显“test.txt”、“test2.txt”、“test3.txt”以及最后“Finish”的内容。

如您所见,在异步函数,我们调用异步函数。getasync()好像是同步的-不then()方法或回调函数,以向下一步发出信号。无论何时await关键字时,执行将暂停,直到 getasync()在移到异步函数中的下一行之前已解析。结果与基于纯承诺的方法相同,使用了一系列的then()方法。

掌握异步函数,包括如何执行await函数并行,读为“JavaScript异步函数简介-承诺简化".

4)JavaScript析构

除了Arrow函数之外,这是我每天使用最多的ES6功能。ES6解构不是一种新特性,而是一种新的赋值语法,它允许您快速地从对象属性和数组中解压缩值,并将它们分配给各个变量。

1
2
3
4
var profile = {name: 'George' , age:39, hobby: 'Tennis' }
var {name, hobby} = profile // destructure profile object
console.log(name) // "George"
console.log(hobby) // "Tennis"

在这里,我使用析构来快速提取namehobby属性的profile对象。

使用别名,您可以使用不同的变量名,而不是从其中提取值的对应对象属性:

1
2
3
4
var profile = {name: 'George' , age:39, hobby: 'Tennis' }
var {name:n, hobby:h} = profile // destructure profile object
console.log(n) // "George"
console.log(h) // "Tennis"

嵌套对象析构

析构也适用于嵌套对象,我一直使用这些对象来快速解压缩复杂JSON请求中的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var jsondata = {
     title: 'Top 5 JavaScript ES6 Features' ,
     Details: {
         date: {
             created: '2017/09/19' ,
             modified: '2017/09/20' ,
         },
         Category: 'JavaScript' ,
     },
     url: '/top-5-es6-features/'
};
 
var {title, Details: {date: {created, modified}}} = jsondata
console.log(title) // 'Top 5 JavaScript ES6 Features'
console.log(created) // '2017/09/19'
console.log(modified) // '2017/09/20'

分解阵列

对数组的解构作用类似于对象,除非在左边使用方括号,而不是左边的大括号:

1
2
3
4
var soccerteam = [ 'George' , 'Dennis' , 'Sandy' ]
var [a, b] = soccerteam // destructure soccerteam array
console.log(a) // "George"
console.log(b) // "Dennis"

在使用逗号(,)解压其元素时,可以跳过某些数组元素:

1
2
3
4
var soccerteam = [ 'George' , 'Dennis' , 'Sandy' ]
var [a,,b] = soccerteam // destructure soccerteam array
console.log(a) // "George"
console.log(b) // "Sandy"

对我来说,析构消除了提取和分配对象属性的所有摩擦,并以传统的方式对数组进行了值处理。若要充分了解ES6破坏的复杂性和潜力,请阅读“掌握ES6:破坏".

5)默认参数和REST参数

最后,我想提出的ES6接下来的两个特性主要是处理函数参数。我们在JavaScript中创建的几乎每个函数都接受用户数据,因此这两个特性肯定会在满月时不止一次地派上用场。

默认参数

在使用应该具有默认值的参数创建函数时,我们都使用了以下模式:

1
2
3
4
5
function getarea(w,h){
var w = w || 10
var h = h || 15
return w * h
}

由于ES6对默认参数的支持,显式定义参数值的测试结束了:

1
2
3
4
function getarea(w=10, h=15){
return w * h
}
getarea(5) // returns 75

更多关于ES6中默认参数的详细信息这里.

休息参数

ES6中的REST参数很容易将函数参数转换为数组,以便于操作。

1
2
3
4
5
function addit(...theNumbers){
     return theNumbers.reduce((prevnum, curnum) => prevnum + curnum, 0) // get the sum of the array elements
}
 
addit(1,2,3,4) // returns 10

通过在命名参数前面加上3个点(.),在该位置输入到函数中的参数将自动转换为数组。

如果没有REST参数,我们将不得不做一些像下面这样复杂的事情手动将参数转换为数组第一:

1
2
3
4
5
6
function addit(theNumbers){
     var numArray = Array.prototype.slice.call(arguments) // force arguments object into array
     return numArray.reduce((prevnum, curnum) => prevnum + curnum, 0)
}
 
addit(1,2,3,4) // returns 10

REST参数仅可应用于函数参数的子集,如以下所示,它只将从第2段开始的参数转换为数组:

1
2
3
4
5
function f1(date, ...lucknumbers){
     return 'The Lucky Numbers for ' + date + ' are: ' + lucknumbers.join( ', ' )
}
 
alert( f1( '2017/09/29' , 3, 32, 43, 52) ) // alerts "The Lucky Numbers for 2017/09/29 are 3,32,43,52"

关于ES6中REST参数的完整规范,看这里.

结语

你同意我的前5项ES6功能吗?你最常使用的是哪一种?请分享以下评论。