tags: [组件]
categories: 底层原理及基础


ES6 常用新特性

let && const

let 命令也用于变量声明,但是作用域为局部
const用于声明一个常量,设定后值不会再改变

箭头函数

箭头函数是 ES6 中新的函数定义形式,function name(arg1, arg2) {…}可以使用(arg1, arg2) => {…}来定义。示例如下:

  1. // JS 普通函数
  2. var arr = [1, 2, 3]
  3. arr.map(function (item) {
  4. console.log(index)
  5. return item + 1
  6. })
  7. // ES6 箭头函数
  8. const arr = [1, 2, 3]
  9. arr.map((item, index) => {
  10. console.log(index)
  11. return item + 1
  12. })

箭头函数存在的意义,第一写起来更加简洁,第二可以解决 ES6 之前函数执行中this是全局变量的问题(没有独立的作用域),看如下代码

  1. function fn() {
  2. console.log('real', this) // {a: 100} ,该作用域下的 this 的真实的值
  3. var arr = [1, 2, 3]
  4. // 普通 JS
  5. arr.map(function (item) {
  6. console.log('js', this) // window 。普通函数,这里打印出来的是全局变量,令人费解
  7. return item + 1
  8. })
  9. // 箭头函数
  10. arr.map(item => {
  11. console.log('es6', this) // {a: 100} 。箭头函数,这里打印的就是父作用域的 this
  12. return item + 1
  13. })
  14. }
  15. fn.call({a: 100})

解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

  1. let [a, b, c] = [1, 2, 3];
  2. //等同于
  3. let a = 1;
  4. let b = 2;
  5. let c = 3;

对象的解构赋值:获取对象的多个属性并且使用一条语句将它们赋给多个变量

  1. var {
  2. StyleSheet,
  3. Text,
  4. View
  5. } = React;
  6. 等同于
  7. var StyleSheet = React.StyleSheet;
  8. var Text = React.Text;
  9. var View = React.Text;

模块化 import导入模块、export导出模块

如果只是输出一个唯一的对象,使用export default即可,代码如下

  1. // 创建 util1.js 文件,内容如
  2. export default {
  3. a: 100
  4. }
  5. // 创建 index.js 文件,内容如
  6. import obj from './util1.js'
  7. console.log(obj)

如果想要输出许多个对象,就不能用default了,且import时候要加{...},代码如下

  1. // 创建 util2.js 文件,内容如
  2. export function fn1() {
  3. alert('fn1')
  4. }
  5. export function fn2() {
  6. alert('fn2')
  7. }
  8. // 创建 index.js 文件,内容如
  9. import { fn1, fn2 } from './util2.js'
  10. fn1()
  11. fn2()

类class

class 其实一直是 JS 的关键字(保留字),但是一直没有正式使用,直到 ES6 。 ES6 的 class 就是取代之前构造函数初始化对象的形式,从语法上更加符合面向对象的写法。例如:

JS 构造函数的写法

  1. function MathHandle(x, y) {
  2. this.x = x;
  3. this.y = y;
  4. }
  5. MathHandle.prototype.add = function () {
  6. return this.x + this.y;
  7. };
  8. var m = new MathHandle(1, 2);
  9. console.log(m.add())

用 ES6 class 的写法

  1. class MathHandle {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. add() {
  7. return this.x + this.y;
  8. }
  9. }
  10. const m = new MathHandle(1, 2);
  11. console.log(m.add())

注意以下几点,全都是关于 class 语法的:

  1. 1class 是一种新的语法形式,是class Name {...}这种形式,和函数的写法完全不一样
  2. 2、两者对比,构造函数函数体的内容要放在 class 中的constructor函数中,constructor即构造器,初始化实例时默认执行
  3. 3class 中函数的写法是add() {...}这种形式,并没有function关键字

使用 class 来实现继承就更加简单了,至少比构造函数实现继承简单很多。看下面例子
JS 构造函数实现继承

  1. // 动物
  2. function Animal() {
  3. this.eat = function () {
  4. console.log('animal eat')
  5. }
  6. }
  7. // 狗
  8. function Dog() {
  9. this.bark = function () {
  10. console.log('dog bark')
  11. }
  12. }
  13. Dog.prototype = new Animal()
  14. // 哈士奇
  15. var hashiqi = new Dog()

ES6 class 实现继承

  1. class Animal {
  2. constructor(name) {
  3. this.name = name
  4. }
  5. eat() {
  6. console.log(`${this.name} eat`)
  7. }
  8. }
  9. class Dog extends Animal {
  10. constructor(name) {
  11. super(name)
  12. this.name = name
  13. }
  14. say() {
  15. console.log(`${this.name} say`)
  16. }
  17. }
  18. const dog = new Dog('哈士奇')
  19. dog.say()
  20. dog.eat()

注意以下两点:

  1. 1、使用extends即可实现继承,更加符合经典面向对象语言的写法,如 Java
  2. 2、子类的constructor一定要执行super(),以调用父类的constructor

Set 和 Map

题目:ES6 中新增的数据类型有哪些?

Set 和 Map 都是 ES6 中新增的数据结构,是对当前 JS 数组和对象这两种重要数据结构的扩展。由于是新增的数据结构,目前尚未被大规模使用,但是作为前端程序员,提前了解是必须做到的。先总结一下两者最关键的地方:
1、Set 类似于数组,但数组可以允许元素重复,Set 不允许元素重复
2、Map 类似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 可以是任何数据类型

Set

Set 实例不允许元素有重复,可以通过以下示例证明。可以通过一个数组初始化一个 Set 实例,或者通过add添加元素,元素不能重复,重复的会被忽略。

  1. // 例1
  2. const set = new Set([1, 2, 3, 4, 4]);
  3. console.log(set) // Set(4) {1, 2, 3, 4}
  4. // 例2
  5. const set = new Set();
  6. [2, 3, 5, 4, 5, 8, 8].forEach(item => set.add(item));
  7. for (let item of set) {
  8. console.log(item);
  9. }
  10. // 2 3 5 4 8

Set 实例的属性和方法有

  1. 1size:获取元素数量。
  2. 2add(value):添加元素,返回 Set 实例本身。
  3. 3delete(value):删除元素,返回一个布尔值,表示删除是否成功。
  4. 4has(value):返回一个布尔值,表示该值是否是 Set 实例的元素。
  5. 5clear():清除所有元素,没有返回值。
  1. const s = new Set();
  2. s.add(1).add(2).add(2); // 添加元素
  3. s.size // 2
  4. s.has(1) // true
  5. s.has(2) // true
  6. s.has(3) // false
  7. s.delete(2);
  8. s.has(2) // false
  9. s.clear();
  10. console.log(s); // Set(0) {}

Set 实例的遍历,可使用如下方法

  1. 1keys():返回键名的遍历器。
  2. 2values():返回键值的遍历器。不过由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys()和values()返回结果一致。
  3. 3entries():返回键值对的遍历器。
  4. 4forEach():使用回调函数遍历每个成员
  1. let set = new Set(['aaa', 'bbb', 'ccc']);
  2. for (let item of set.keys()) {
  3. console.log(item);
  4. }
  5. // aaa
  6. // bbb
  7. // ccc
  8. for (let item of set.values()) {
  9. console.log(item);
  10. }
  11. // aaa
  12. // bbb
  13. // ccc
  14. for (let item of set.entries()) {
  15. console.log(item);
  16. }
  17. // ["aaa", "aaa"]
  18. // ["bbb", "bbb"]
  19. // ["ccc", "ccc"]
  20. set.forEach((value, key) => console.log(key + ' : ' + value))
  21. // aaa : aaa
  22. // bbb : bbb
  23. // ccc : ccc

Map

Map 的用法和普通对象基本一致,先看一下它能用非字符串或者数字作为 key 的特性。

  1. const map = new Map();
  2. const obj = {p: 'Hello World'};
  3. map.set(obj, 'OK')
  4. map.get(obj) // "OK"
  5. map.has(obj) // true
  6. map.delete(obj) // true
  7. map.has(obj) // false

需要使用new Map()初始化一个实例,下面代码中set get has delete顾名即可思义(下文也会演示)。其中,map.set(obj, ‘OK’)就是用对象作为的 key (不光可以是对象,任何数据类型都可以),并且后面通过map.get(obj)正确获取了

Map 实例的属性和方法如下:

1、size:获取成员的数量 2、set:设置成员 key 和 value 3、get:获取成员属性值 4、has:判断成员是否存在 5、delete:删除成员 6、clear:清空所有

  1. const map = new Map();
  2. map.set('aaa', 100);
  3. map.set('bbb', 200);
  4. map.size // 2
  5. map.get('aaa') // 100
  6. map.has('aaa') // true
  7. map.delete('aaa')
  8. map.has('aaa') // false
  9. map.clear()

Map 实例的遍历方法有:

1、keys():返回键名的遍历器。 2、values():返回键值的遍历器。 3、entries():返回所有成员的遍历器。 4、forEach():遍历 Map 的所有成员

  1. const map = new Map();
  2. map.set('aaa', 100);
  3. map.set('bbb', 200);
  4. for (let key of map.keys()) {
  5. console.log(key);
  6. }
  7. // "aaa"
  8. // "bbb"
  9. for (let value of map.values()) {
  10. console.log(value);
  11. }
  12. // 100
  13. // 200
  14. for (let item of map.entries()) {
  15. console.log(item[0], item[1]);
  16. }
  17. // aaa 100
  18. // bbb 200
  19. // 或者
  20. for (let [key, value] of map.entries()) {
  21. console.log(key, value);
  22. }
  23. // aaa 100
  24. // bbb 200

Promise

  Promise是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。
  Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅。
  简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1
  三个状态:pending、fulfilled、rejected

两个过程: 1、pending→fulfilled(resolve) 2、pending→rejected(reject) 当然还有其他概念,如catch、 Promise.all/race,这里就不展开了

  1. new Promise((resolve,reject)=>{
  2. $.ajax({
  3. url : "xxxxx",
  4. type : "post"
  5. success(res){
  6. resolve(res)
  7. },
  8. error(err){
  9. rejecterr
  10. }
  11. });
  12. }).then(()=>{
  13. },()=>{
  14. })

  ES6常用新特性

let && const

  let 命令也用于变量声明,但是作用域为局部
const用于声明一个常量,设定后值不会再改变

箭头函数

箭头函数是 ES6 中新的函数定义形式,function name(arg1, arg2) {…}可以使用(arg1, arg2) => {…}来定义。示例如下:

  1. // JS 普通函数
  2. var arr = [1, 2, 3]
  3. arr.map(function (item) {
  4. console.log(index)
  5. return item + 1
  6. })
  7. // ES6 箭头函数
  8. const arr = [1, 2, 3]
  9. arr.map((item, index) => {
  10. console.log(index)
  11. return item + 1
  12. })

箭头函数存在的意义,第一写起来更加简洁,第二可以解决 ES6 之前函数执行中this是全局变量的问题(没有独立的作用域),看如下代码

  1. function fn() {
  2. console.log('real', this) // {a: 100} ,该作用域下的 this 的真实的值
  3. var arr = [1, 2, 3]
  4. // 普通 JS
  5. arr.map(function (item) {
  6. console.log('js', this) // window 。普通函数,这里打印出来的是全局变量,令人费解
  7. return item + 1
  8. })
  9. // 箭头函数
  10. arr.map(item => {
  11. console.log('es6', this) // {a: 100} 。箭头函数,这里打印的就是父作用域的 this
  12. return item + 1
  13. })
  14. }
  15. fn.call({a: 100})

解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

  1. let [a, b, c] = [1, 2, 3];
  2. //等同于
  3. let a = 1;
  4. let b = 2;
  5. let c = 3;

对象的解构赋值:获取对象的多个属性并且使用一条语句将它们赋给多个变量

  1. var {
  2. StyleSheet,
  3. Text,
  4. View
  5. } = React;
  6. 等同于
  7. var StyleSheet = React.StyleSheet;
  8. var Text = React.Text;
  9. var View = React.Text;

模块化 import导入模块、export导出模块

如果只是输出一个唯一的对象,使用export default即可,代码如下

  1. // 创建 util1.js 文件,内容如
  2. export default {
  3. a: 100
  4. }
  5. // 创建 index.js 文件,内容如
  6. import obj from './util1.js'
  7. console.log(obj)

如果想要输出许多个对象,就不能用default了,且import时候要加{...},代码如下

  1. // 创建 util2.js 文件,内容如
  2. export function fn1() {
  3. alert('fn1')
  4. }
  5. export function fn2() {
  6. alert('fn2')
  7. }
  8. // 创建 index.js 文件,内容如
  9. import { fn1, fn2 } from './util2.js'
  10. fn1()
  11. fn2()

类class

class 其实一直是 JS 的关键字(保留字),但是一直没有正式使用,直到 ES6 。 ES6 的 class 就是取代之前构造函数初始化对象的形式,从语法上更加符合面向对象的写法。例如:

JS 构造函数的写法

  1. function MathHandle(x, y) {
  2. this.x = x;
  3. this.y = y;
  4. }
  5. MathHandle.prototype.add = function () {
  6. return this.x + this.y;
  7. };
  8. var m = new MathHandle(1, 2);
  9. console.log(m.add())

用 ES6 class 的写法

  1. class MathHandle {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. add() {
  7. return this.x + this.y;
  8. }
  9. }
  10. const m = new MathHandle(1, 2);
  11. console.log(m.add())

注意以下几点,全都是关于 class 语法的:

  1. 1class 是一种新的语法形式,是class Name {...}这种形式,和函数的写法完全不一样
  2. 2、两者对比,构造函数函数体的内容要放在 class 中的constructor函数中,constructor即构造器,初始化实例时默认执行
  3. 3class 中函数的写法是add() {...}这种形式,并没有function关键字

使用 class 来实现继承就更加简单了,至少比构造函数实现继承简单很多。看下面例子
JS 构造函数实现继承

  1. // 动物
  2. function Animal() {
  3. this.eat = function () {
  4. console.log('animal eat')
  5. }
  6. }
  7. // 狗
  8. function Dog() {
  9. this.bark = function () {
  10. console.log('dog bark')
  11. }
  12. }
  13. Dog.prototype = new Animal()
  14. // 哈士奇
  15. var hashiqi = new Dog()

ES6 class 实现继承

  1. class Animal {
  2. constructor(name) {
  3. this.name = name
  4. }
  5. eat() {
  6. console.log(`${this.name} eat`)
  7. }
  8. }
  9. class Dog extends Animal {
  10. constructor(name) {
  11. super(name)
  12. this.name = name
  13. }
  14. say() {
  15. console.log(`${this.name} say`)
  16. }
  17. }
  18. const dog = new Dog('哈士奇')
  19. dog.say()
  20. dog.eat()

注意以下两点:

  1. 1、使用extends即可实现继承,更加符合经典面向对象语言的写法,如 Java
  2. 2、子类的constructor一定要执行super(),以调用父类的constructor

Set 和 Map

题目:ES6 中新增的数据类型有哪些?

Set 和 Map 都是 ES6 中新增的数据结构,是对当前 JS 数组和对象这两种重要数据结构的扩展。由于是新增的数据结构,目前尚未被大规模使用,但是作为前端程序员,提前了解是必须做到的。先总结一下两者最关键的地方:
1、Set 类似于数组,但数组可以允许元素重复,Set 不允许元素重复
2、Map 类似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 可以是任何数据类型

Set

Set 实例不允许元素有重复,可以通过以下示例证明。可以通过一个数组初始化一个 Set 实例,或者通过add添加元素,元素不能重复,重复的会被忽略。

  1. // 例1
  2. const set = new Set([1, 2, 3, 4, 4]);
  3. console.log(set) // Set(4) {1, 2, 3, 4}
  4. // 例2
  5. const set = new Set();
  6. [2, 3, 5, 4, 5, 8, 8].forEach(item => set.add(item));
  7. for (let item of set) {
  8. console.log(item);
  9. }
  10. // 2 3 5 4 8

Set 实例的属性和方法有

  1. 1size:获取元素数量。
  2. 2add(value):添加元素,返回 Set 实例本身。
  3. 3delete(value):删除元素,返回一个布尔值,表示删除是否成功。
  4. 4has(value):返回一个布尔值,表示该值是否是 Set 实例的元素。
  5. 5clear():清除所有元素,没有返回值。
  1. const s = new Set();
  2. s.add(1).add(2).add(2); // 添加元素
  3. s.size // 2
  4. s.has(1) // true
  5. s.has(2) // true
  6. s.has(3) // false
  7. s.delete(2);
  8. s.has(2) // false
  9. s.clear();
  10. console.log(s); // Set(0) {}

Set 实例的遍历,可使用如下方法

  1. 1keys():返回键名的遍历器。
  2. 2values():返回键值的遍历器。不过由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys()和values()返回结果一致。
  3. 3entries():返回键值对的遍历器。
  4. 4forEach():使用回调函数遍历每个成员
  1. let set = new Set(['aaa', 'bbb', 'ccc']);
  2. for (let item of set.keys()) {
  3. console.log(item);
  4. }
  5. // aaa
  6. // bbb
  7. // ccc
  8. for (let item of set.values()) {
  9. console.log(item);
  10. }
  11. // aaa
  12. // bbb
  13. // ccc
  14. for (let item of set.entries()) {
  15. console.log(item);
  16. }
  17. // ["aaa", "aaa"]
  18. // ["bbb", "bbb"]
  19. // ["ccc", "ccc"]
  20. set.forEach((value, key) => console.log(key + ' : ' + value))
  21. // aaa : aaa
  22. // bbb : bbb
  23. // ccc : ccc

Map

Map 的用法和普通对象基本一致,先看一下它能用非字符串或者数字作为 key 的特性。

  1. const map = new Map();
  2. const obj = {p: 'Hello World'};
  3. map.set(obj, 'OK')
  4. map.get(obj) // "OK"
  5. map.has(obj) // true
  6. map.delete(obj) // true
  7. map.has(obj) // false

需要使用new Map()初始化一个实例,下面代码中set get has delete顾名即可思义(下文也会演示)。其中,map.set(obj, ‘OK’)就是用对象作为的 key (不光可以是对象,任何数据类型都可以),并且后面通过map.get(obj)正确获取了

Map 实例的属性和方法如下:

1、size:获取成员的数量 2、set:设置成员 key 和 value 3、get:获取成员属性值 4、has:判断成员是否存在 5、delete:删除成员 6、clear:清空所有

  1. const map = new Map();
  2. map.set('aaa', 100);
  3. map.set('bbb', 200);
  4. map.size // 2
  5. map.get('aaa') // 100
  6. map.has('aaa') // true
  7. map.delete('aaa')
  8. map.has('aaa') // false
  9. map.clear()

Map 实例的遍历方法有:

1、keys():返回键名的遍历器。 2、values():返回键值的遍历器。 3、entries():返回所有成员的遍历器。 4、forEach():遍历 Map 的所有成员

  1. const map = new Map();
  2. map.set('aaa', 100);
  3. map.set('bbb', 200);
  4. for (let key of map.keys()) {
  5. console.log(key);
  6. }
  7. // "aaa"
  8. // "bbb"
  9. for (let value of map.values()) {
  10. console.log(value);
  11. }
  12. // 100
  13. // 200
  14. for (let item of map.entries()) {
  15. console.log(item[0], item[1]);
  16. }
  17. // aaa 100
  18. // bbb 200
  19. // 或者
  20. for (let [key, value] of map.entries()) {
  21. console.log(key, value);
  22. }
  23. // aaa 100
  24. // bbb 200

Promise

  Promise是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。
  Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅。
  简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1
  三个状态:pending、fulfilled、rejected

两个过程: 1、pending→fulfilled(resolve) 2、pending→rejected(reject) 当然还有其他概念,如catch、 Promise.all/race,这里就不展开了

  1. new Promise((resolve,reject)=>{
  2. $.ajax({
  3. url : "xxxxx",
  4. type : "post"
  5. success(res){
  6. resolve(res)
  7. },
  8. error(err){
  9. rejecterr
  10. }
  11. });
  12. }).then(()=>{
  13. },()=>{
  14. })

ES7 新特性

1.Array.prototype.includes
2.Exponentiation Operator(求幂运算)

Array.prototype.includes

Array.prototype.includes用法都容易和简单。它是一个替代indexOf,开发人员用来检查数组中是否存在值,indexOf是一种尴尬的使用,因为它返回一个元素在数组中的位置或者-1当这样的元素不能被找到的情况下。所以它返回一个数字,而不是一个布尔值。开发人员需要实施额外的检查。在ES6,要检查是否存在值你需要做一些如下图所示小技巧,因为他们没有匹配到值,Array.prototype.indexOf返回-1变成了true(转换成true),但是当匹配的元素为0位置时候,该数组包含元素,却变成了false。

  1. let arr = [‘react‘, angular‘, vue‘]
  2. // WRONG
  3. if (arr.indexOf(‘react‘)) { // 0 -> evaluates to false, definitely as we expected
  4. console.log(‘Can use React‘) // this line would never be executed
  5. }
  6. // Correct
  7. if (arr.indexOf(‘react‘) !== -1) {
  8. console.log(‘Can use React‘)
  9. }

或者使用一点点hack 位运算符 ~ 使代码更加紧凑一些,因为~(位异或)对任何数字相当于-(a + 1):

  1. let arr = [‘react‘, angular‘, vue‘]
  2. // Correct
  3. if (~arr.indexOf(‘react‘)) {
  4. console.log(‘Can use React‘)
  5. }

在ES7中使用includes代码如下:

  1. let arr = [‘react‘, angular‘, vue‘]
  2. // Correct
  3. if (arr.includes(‘react‘)) {
  4. console.log(‘Can use React‘)
  5. }

还能在字符串中使用includes:

  1. let str = React Quickly
  2. // Correct
  3. if (str.toLowerCase().includes(‘react‘)) { // true
  4. console.log(‘Found "react"‘)
  5. }

除了增强了可读性语义化,实际上给开发者返回布尔值,而不是匹配的位置。

includes也可以在NaN(非数字)使用。最后 ,includes第二可选参数fromIndex,这对于优化是有好处的,因为它允许从特定位置开始寻找匹配。
更多例子:

  1. console.log([1, 2, 3].includes(2)) // === true)
  2. console.log([1, 2, 3].includes(4)) // === false)
  3. console.log([1, 2, NaN].includes(NaN)) // === true)
  4. console.log([1, 2, -0].includes(+0)) // === true)
  5. console.log([1, 2, +0].includes(-0)) // === true)
  6. console.log([‘a‘, b‘, c‘].includes(‘a‘)) // === true)
  7. console.log([‘a‘, b‘, c‘].includes(‘a‘, 1)) // === false)

总而言之,includes在一个数组或者列表中检查是否存在一个值,给任何开发人员带来简单性。

Exponentiation Operator(求幂运算)

求幂运算大多数是做一些数学计算,对于3D,VR,SVG还有数据可视化非常有用。在ES6或者早些版本,不得不创建一个循环,创建一个递归函数或者使用Math.pow,如果忘记了什么是指数,当你有相同数字(基数)自相相乘多次(指数)。例如,7的3次方是777

所以在ES6/2015ES,你能使用Math.pow创建一个短的递归箭头函数:

  1. calculateExponent = (base, exponent) => base*((--exponent>1)?calculateExponent(base, exponent):base)
  2. console.log(calculateExponent(7,12) === Math.pow(7,12)) // true
  3. console.log(calculateExponent(2,7) === Math.pow(2,7)) // true

现在在ES7 /ES2016,以数学向导的开发者可以使用更短的语法:

  1. let a = 7 ** 12
  2. let b = 2 ** 7
  3. console.log(a === Math.pow(7,12)) // true
  4. console.log(b === Math.pow(2,7)) // true

开发者还可以操作结果:

  1. let a = 7
  2. a **= 12
  3. let b = 2
  4. b **= 7
  5. console.log(a === Math.pow(7,12)) // true
  6. console.log(b === Math.pow(2,7)) // true

ES8 新特性

  1. 1Object.values/Object.entries
  2. 2String padding(字符串填充)
  3. 3Object.getOwnPropertyDescriptors
  4. 4、函数参数列表和调用中的尾逗号(Trailing commas
  5. 5、异步函数(Async Functions

Object.values/Object.entries

Object.values和 Object.entries是在ES2017规格中,它和Object.keys类似,返回数组类型,其序号和Object.keys序号对应。类似python中的dict.iteritems()。

Object.values,Object.entries和Object.keys各自项返回是数组,相对应包括key,value或者可枚举特定对象property/attribute

  1. let obj = {a: 1, b: 2, c: 3}
  2. Object.keys(obj).forEach((key, index)=>{
  3. console.log(key, obj[key])
  4. })

而使用ES6/ES2015 中for/of稍微好点:

  1. let obj = {a: 1, b: 2, c: 3}
  2. for (let key of Object.keys(obj)) {
  3. console.log(key, obj[key])
  4. }

Object.values返回对象自身可以迭代属性值(values)为数组类型。我们最好使用Array.prototype.forEach迭代它,结合ES6的箭头函数隐形返回值:

  1. let obj = {a: 1, b: 2, c: 3}
  2. Object.values(obj).forEach(value=>console.log(value)) // 1, 2, 3

String padding(字符串填充)

String.prototype.padStart 和 String.prototype.padEnd在javascript字符操作是一个不错的体验,帮助避免依赖而外的库
padStart()在开始部位填充,返回一个给出长度的字符串,填充物给定字符串,把字符串填充到期望的长度。从字符串的左边开始(至少大部分西方语言),一个经典例子是使用空格创建列:

  1. console.log(‘react‘.padStart(10).length) // " react" is 10
  2. console.log(‘backbone‘.padStart(10).length) // " backbone" is 10

Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptors允许创建真实的对象浅副本并创建子类,它通过给开发者描述符来做到这一点.在Object.create(prototype, object)放入描述符后,返回一个真正的浅拷贝

  1. Object.create(
  2. Object.getPrototypeOf(obj),
  3. Object.getOwnPropertyDescriptors(obj)
  4. )

或者你可以合并两个对象target和source如下:

  1. Object.defineProperties(
  2. target,
  3. Object.getOwnPropertyDescriptors(source)
  4. )

两种描述符号类型:

  1. 1.数据描述符(Data descriptor
  2. 2.存取器描述符(Accessor descriptor

存取描述符有必须属性:get 或者set或者get和set两个就是如你所想的getter和setter函数,然后存取描述符还有可选属性configurable和enumerable

  1. let azatsBooks = {
  2. books: ['React Quickly'],
  3. get latest () {
  4. let numberOfBooks = this.books.length
  5. if (numberOfBooks == 0) return undefined
  6. return this.books[numberOfBooks - 1]
  7. }
  8. }

函数参数列表和调用中的尾逗号

尾逗号在函数定义中只是一个纯粹语法变化,在ES5中,将会非法语法,在函数参数后面应该是没有逗号的:

  1. var f = function(a,
  2. b,
  3. c,
  4. d) { // NO COMMA!
  5. // ...
  6. console.log(d)
  7. }
  8. f(1,2,3,'this')

在ES8中,这种尾逗号是没有问题的:

  1. var f = function(a,
  2. b,
  3. c,
  4. d,
  5. ) { // COMMA? OK!
  6. // ...
  7. console.log(d)
  8. }
  9. f(1,2,3,'this')

异步函数

异步函数(或者async/await)特性操作是Promise最重要的功能,开发者定义一个asyc函数里面不包含或者包含await 基于Promise异步操作
在ES6中我们可以使用Promise,Axios库向GraphQL服务器发送一个请求:

  1. axios.get(`/q?query=${query}`)
  2. .then(response => response.data)
  3. .then(data => {
  4. this.props.processfetchedData(data) // Defined somewhere else
  5. })
  6. .catch(error => console.log(error))

任何一个Promise库都能兼容新的异步函数,我们可以使用同步try/catch做错误处理

  1. async fetchData(url) => {
  2. try {
  3. const response = await axios.get(`/q?query=${query}`)
  4. const data = response.data
  5. this.props.processfetchedData(data)
  6. } catch (error) {
  7. console.log(error)
  8. }
  9. }

异步函数返回一个Promise,所以我们像下面可以继续执行流程:

  1. async fetchData(query) => {
  2. try {
  3. const response = await axios.get(`/q?query=${query}`)
  4. const data = response.data
  5. return data
  6. } catch (error) {
  7. console.log(error)
  8. }
  9. }
  10. fetchData(query).then(data => {
  11. this.props.processfetchedData(data)
  12. })

你可以看到这段代码在(Babel REPL)生效。请注意,这个例子中,Axios库被代替的,是通过模拟来做相同功能,而HTTP请求通过setTimout代替:

  1. let axios = { // mocks
  2. get: function(x) {
  3. return new Promise(resolve => {
  4. setTimeout(() => {
  5. resolve({data: x})
  6. }, 2000)
  7. })
  8. }}
  9. let query = 'mangos'
  10. async function fetchData(query) {
  11. try {
  12. const response = await axios.get(`/q?query=${query}`)
  13. const data = response.data
  14. return data
  15. } catch (error) {
  16. console.log(error)
  17. }
  18. }
  19. fetchData(query).then(data => {
  20. console.log(data) // Got data 2s later... Can use data!
  21. })

async/await,我们的代码执行异步看起来像执行同步一样

ES9 新特性

Array.prototype.flat(depth)

  1. const numbers = [1, 2, [3, 4, [5, 6]]];
  2. // Considers default depth of 1
  3. numbers.flat();
  4. > [1, 2, 3, 4, [5, 6]]
  5. // With depth of 2
  6. numbers.flat(2);
  7. > [1, 2, 3, 4, 5, 6]
  8. // Executes two flat operations
  9. numbers.flat().flat();
  10. > [1, 2, 3, 4, 5, 6]
  11. // Flattens recursively until the array contains no nested arrays
  12. numbers.flat(Infinity)
  13. > [1, 2, 3, 4, 5, 6]

Object.fromEntries

Object.entries 的逆运算,注意由于对象和数组仍然是不同的数据结构,在使用Object.fromEntries转化键值对数组为对象时,会自动合并key相同的项,value值以最后的value决定;

  1. let entries = [
  2. [ 'key1', 22 ],
  3. [ 'key2', 22 ],
  4. [ 'key3', 21],
  5. [ 'key2', 20 ]
  6. ]
  7. let obj = Object.fromEntries(entries);
  8. // { key1: 22, key2: 20, key3: 21 }