10分钟学会ES7+ES8 上

简介: 10分钟学会ES7+ES8 上

原文链接: www.cnblogs.com


撰文为何

身为一个前端开发者,ECMAScript(以下简称ES)早已广泛应用在我们的工作当中。了解ECMA机构流程的人应该知道,标准委员会会在每年的6月份正式发布一次规范的修订,而这次的发布也将作为当年的正式版本。以后的改动,都会基于上一版本进行修改。所以,我们这次就基于ES6的版本对ES7、ES8版本的新增以及修改内容,做一次简要的总结,方便我们快速开发。


ES7新特性

ES7在ES6的基础上添加了三项内容:求幂运算符(**)Array.prototype.includes()方法、函数作用域中严格模式的变更。

Array.prototype.includes()方法

includes()的作用,是查找一个值在不在数组里,若在,则返回true,反之返回false。 基本用法:

['a', 'b', 'c'].includes('a')     // true
['a', 'b', 'c'].includes('d')     // false

 

Array.prototype.includes()方法接收两个参数:要搜索的值和搜索的开始索引。当第二个参数被传入时,该方法会从索引处开始往后搜索(默认索引值为0)。若搜索值在数组中存在则返回true,否则返回false。 且看下面示例:

['a', 'b', 'c', 'd'].includes('b')         // true
['a', 'b', 'c', 'd'].includes('b', 1)      // true
['a', 'b', 'c', 'd'].includes('b', 2)      // false

 

那么,我们会联想到ES6里数组的另一个方法indexOf,下面的示例代码是等效的:

['a', 'b', 'c'].includes('a')          //true
['a', 'b', 'c'].indexOf('a') > -1      //true

 

此时,就有必要来比较下两者的优缺点和使用场景了。

  • 简便性

从这一点上来说,includes略胜一筹。熟悉indexOf的同学都知道,indexOf返回的是某个元素在数组中的下标值,若想判断某个元素是否在数组里,我们还需要做额外的处理,即判断该返回值是否>-1。而includes则不用,它直接返回的便是Boolean型的结果。

  • 精确性

两者使用的都是 === 操作符来做值的比较。但是includes()方法有一点不同,两个NaN被认为是相等的,即使在NaN === NaN结果是false的情况下。这一点和indexOf()的行为不同,indexOf()严格使用===判断。请看下面示例代码:

let demo = [1, NaN, 2, 3]
demo.indexOf(NaN)        //-1
demo.includes(NaN)       //true

 

上述代码中,indexOf()方法返回-1,即使NaN存在于数组中,而includes()则返回了true。

提示:由于它对NaN的处理方式与indexOf不同,假如你只想知道某个值是否在数组中而并不关心它的索引位置,建议使用includes()。如果你想获取一个值在数组中的位置,那么你只能使用indexOf方法。

includes()还有一个怪异的点需要指出,在判断 +0 与 -0 时,被认为是相同的。

[1, +0, 3, 4].includes(-0)    //true
[1, +0, 3, 4].indexOf(-0)     //1

 

在这一点上,indexOf()includes()的处理结果是一样的,前者同样会返回 +0 的索引值。

注意:在这里,需要注意一点,includes()只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些,是无法判断的。

求幂运算符(**)

基本用法

3 ** 2           // 9

效果同:

Math.pow(3, 2)   // 9

** 是一个用于求幂的中缀算子,比较可知,中缀符号比函数符号更简洁,这也使得它更为可取。 下面让我们扩展下思路,既然说**是一个运算符,那么它就应该能满足类似加等的操作,我们姑且称之为幂等,例如下面的例子,a的值依然是9:

let a = 3
a **= 2
// 9

 

对比下其他语言的指数运算符:

  • Python: x ** y
  • CoffeeScript: x ** y
  • F#: x ** y
  • Ruby: x ** y
  • Perl: x ** y
  • Lua, Basic, MATLAB: x ^ y

不难发现,ES的这个新特性是从其他语言(Python,Ruby等)模仿而来的。

ES8新特性

异步函数(Async functions)

为什么要引入async

众所周知,JavaScript语言的执行环境是“单线程”的,那么异步编程对JavaScript语言来说就显得尤为重要。以前我们大多数的做法是使用回调函数来实现JavaScript语言的异步编程。回调函数本身没有问题,但如果出现多个回调函数嵌套,例如:进入某个页面,需要先登录,拿到用户信息之后,调取用户商品信息,代码如下:

this.$http.jsonp('/login', (res) => {
  this.$http.jsonp('/getInfo', (info) => {
    // do something
  })
})

 

假如上面还有更多的请求操作,就会出现多重嵌套。代码很快就会乱成一团,这种情况就被称为“回调函数地狱”(callback hell)。

于是,我们提出了Promise,它将回调函数的嵌套,改成了链式调用。写法如下:

var promise = new Promise((resolve, reject) => {
  this.login(resolve)
})
.then(() => this.getInfo())
.catch(() => { console.log("Error") })

 

从上面可以看出,Promise的写法只是回调函数的改进,使用then方法,只是让异步任务的两段执行更清楚而已。Promise的最大问题是代码冗余,请求任务多时,一堆的then,也使得原来的语义变得很不清楚。此时我们引入了另外一种异步编程的机制:Generator。

Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。一个简单的例子用来说明它的用法:

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();

 

上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。上述代码分步执行如下:

hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }

 

Generator函数的机制更符合我们理解的异步编程思想。

用户登录的例子,我们用Generator来写,如下:

var gen = function* () {
  const f1 = yield this.login()
  const f2 = yield this.getInfo()
};

 

虽然Generator将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。此时,我们便希望能出现一种能自动执行Generator函数的方法。我们的主角来了:async/await。

ES8引入了async函数,使得异步操作变得更加方便。简单说来,它就是Generator函数的语法糖。

async function asyncFunc(params) {
  const result1 = await this.login()
  const result2 = await this.getInfo()
}

 

是不是更加简洁易懂呢?


变体

异步函数存在以下四种使用形式:

  • 函数声明: async function foo() {}
  • 函数表达式: const foo = async function() {}
  • 对象的方式: let obj = { async foo() {} }
  • 箭头函数: const foo = async () => {}


常见用法汇总

处理单个异步结果:

async function asyncFunc() {
  const result = await otherAsyncFunc();
  console.log(result);
}

 

顺序处理多个异步结果:

async function asyncFunc() {
  const result1 = await otherAsyncFunc1();
  console.log(result1);
  const result2 = await otherAsyncFunc2();
  console.log(result2);
}

 

并行处理多个异步结果:

async function asyncFunc() {
  const [result1, result2] = await Promise.all([
    otherAsyncFunc1(),
    otherAsyncFunc2()
  ]);
  console.log(result1, result2);
}

 

处理错误:

async function asyncFunc() {
  try {
    await otherAsyncFunc();
  } catch (err) {
    console.error(err);
  }
}

 

若想进一步了解async的具体实践,可参见阮一峰的博客文章,链接奉上:es6.ruanyifeng.com/#docs/async


Object.entries()和Object.values()

Object.entries()

如果一个对象是具有键值对的数据结构,则每一个键值对都将会编译成一个具有两个元素的数组,这些数组最终会放到一个数组中,返回一个二维数组。简言之,该方法会将某个对象的可枚举属性与值按照二维数组的方式返回。若目标对象是数组时,则会将数组的下标作为键值返回。例如:

Object.entries({ one: 1, two: 2 })    //[['one', 1], ['two', 2]]
Object.entries([1, 2])                //[['0', 1], ['1', 2]]

 

注意:键值对中,如果键的值是Symbol,编译时将会被忽略。例如:

Object.entries({ [Symbol()]: 1, two: 2 })       //[['two', 2]]

Object.entries()返回的数组的顺序与for-in循环保持一致,即如果对象的key值是数字,则返回值会对key值进行排序,返回的是排序后的结果。例如:

Object.entries({ 3: 'a', 4: 'b', 1: 'c' })    //[['1', 'c'], ['3', 'a'], ['4', 'b']]

 

使用Object.entries(),我们还可以进行对象属性的遍历。例如:

let obj = { one: 1, two: 2 };
for (let [k,v] of Object.entries(obj)) {
  console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
}
//输出结果如下:
'one': 1
'two': 2

 


目录
相关文章
|
SQL 缓存 Java
框架分析(9)-Hibernate
框架分析(9)-Hibernate
|
数据安全/隐私保护
|
8月前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
1142 9
|
JSON 安全 数据格式
Flask 高级应用:使用蓝图模块化应用和 JWT 实现安全认证
本文将探讨 Flask 的两个高级特性:蓝图(Blueprints)和 JSON Web Token(JWT)认证。蓝图让我们可以将应用模块化,以便更好地组织代码;而 JWT 认证是现代 Web 应用中常见的一种安全机制。
|
缓存 监控 前端开发
java简历2年经验编写教程+面试题
是花了我很多天的心思,用心打造出来的Java简历分析模板,适合新手包装成有一点工作年限(1-2年),但又不会太老手的简历;让你的简历做得跟别人不一样;
4323 0
|
数据可视化 数据挖掘 数据处理
Python对Excel两列数据进行运算【从基础到高级的全面指南】
【7月更文挑战第6天】使用Python的`pandas`库处理Excel数据,涉及安装`pandas`和`openpyxl`,读取数据如`df = pd.read_excel('data.xlsx')`,进行运算如`df['Sum'] = df['Column1'] + df['Column2']`,并将结果写回Excel。`pandas`还支持数据筛选、分组、可视化、异常处理和性能优化。通过熟练运用这些功能,可以高效分析Excel表格。
|
Android开发 开发者
安卓投屏神器 Scrcpy安 报错ERROR: Could not find any ADB device
使用Scrcpy安卓投屏工具时遇到报错,问题根源是未开启开发者模式。解决步骤:进入设置,点击【关于手机】→连续点击版本号激活开发者模式,然后在【系统设置】→【开发者选项】中开启USB调试。参照此方法后可正常执行。Scrcpy软件下载链接和GitHub页面也已提供。
1844 1
|
存储 C# C++
从C++角度讲解C#Out和ref的区别
从C++角度讲解C#Out和ref的区别
289 0
|
算法 C语言
【数学建模系列】TOPSIS法的算法步骤及实战应用——MATLAB实现
客观评价方法中的一种,亦称为理想解法,是一种有效的多指标评价方法。这种方法通过构造评价问题的正理想解和负理想解,即各指标的最优解和最劣解,通过计算每个方案到理想方案的相对贴近度,即靠近止理想解和远离负理想解的程度,来对方案进行排序,从而选出最优方案。
【数学建模系列】TOPSIS法的算法步骤及实战应用——MATLAB实现
App开放接口api安全:Token签名sign的设计与实现
在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些 接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等,但是为了安全起见让用户暴露的明文密码次数越少越好,我们一般在web项目 中,大多数采用保存的session中,然后在存一份到cookie中,来保持用户的回话有效性。