ES6、ES7常用特性

一、ES6(ES2015)新特性

1、支持let和const
在之前JS是没有块级作用域的,const与let填补了这方便的空白,const与let都是块级作用域。

  • 使用var定义的变量为函数级作用域:
{
  var a = 10;
}
console.log(a); // 输出10
  • 使用let定义的变量为块级作用域:
{
  let a = 10;
}
console.log(a); //Uncaught ReferenceError: a is not defined

2、箭头函数
=>不只是关键字function的简写,箭头函数与包围它的代码共享同一个this,能很好的解决this的指向问题。
箭头函数的结构:箭头函数的箭头=>之前是一个空括号、单个的参数名、或用括号括起的多个参数名,而箭头之后可以是一个表达式(作为函数的返回值),或者是用花括号括起的函数体(需要自行通过return来返回值,否则返回的是undefined)。

// ES5
var mul = function(x, y) {
   return x * y;
}

// ES6
const mul = (x, y) => x * y;
// 或者
const mul = (x, y) => { return x * y };

3、类(class)
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

  • constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
class Car {
  constructor(brand) {
    this.carName = brand;
  }
}
let myCar = new Car("Ford");
console.log(myCar); // Car {carName: "Ford"}
  • 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

4、函数参数默认值
ES6支持在定义函数的时候为其设置默认值:

function myFunction(x, y = 10) {
  // y is 10 if not passed or undefined
  return x + y;
}
myFunction(5); // 15

5、模块化 module
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
严格模式主要有以下限制:
<1>变量必须声明后再使用
<2>函数的参数不能有同名属性,否则报错
<3>不能使用with语句
<4>不能对只读属性赋值,否则报错
<5>不能使用前缀 0 表示八进制数,否则报错
<6>不能删除不可删除的属性,否则报错
<7>不能删除变量delete prop,会报错,只能删除属性delete global[prop]
<8>eval不会在它的外层作用域引入变量
<9>eval和arguments不能被重新赋值
<10>arguments不会自动反映函数参数的变化
<11>不能使用arguments.callee
<12>不能使用arguments.caller
<13>禁止this指向全局对象
<14>不能使用fn.caller和fn.arguments获取函数调用的堆栈
<15>增加了保留字(比如protected、static和interface)

模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

  • export
    一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量
//一、 输出变量
export var year = 2020;
// 或者
var year = 2020;
export { year };

//二、输出函数或类(class)
export function multiply(x, y) {
  return x * y;
};

//或者使用as关键字,重命名函数v1和v2的对外接口。重命名后,v2可以用不同的名字输出两次
function v1() { ... }
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};
// 三、输出默认
export default function foo() {
  console.log('foo');
}
  • import
    使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径。如果不带有路径,只是一个模块名,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。
// 一、输入变量
import { firstName, lastName, year } from './profile.js';
 // 使用as关键字,将输入的变量重命名。
import { lastName as surname } from './profile.js';
// 二、整体加载
import * as circle from './circle';

6、模版字符串
ES6支持模板字符串,使得字符串的拼接更加的简洁、直观。在ES6中通过${}就可以完成字符串的拼接,只需要将变量放在大括号之中。

//不使用模板字符串:
var name = 'Your name is ' + first + ' ' + last + '.'
 
//使用模板字符串:
var name = `Your name is ${first} ${last}.`

7、解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

  • 数组的解构赋值
let [a, b, c] = [1, 2, 3];
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"
// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

let [x, y = 'b'] = ['a']; // x='a', y='b'

  • 对象的解构赋值
    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined

const { log } = console;
log('hello') // hello

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
  • 字符串的解构赋值
    字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

// 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len // 5
  • 数值和布尔值的解构赋值
    解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true
// 数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。
  • 函数参数的解构赋值
function add([x, y]){
  return x + y;
}

add([1, 2]); // 3
  • 注意点
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

// 正确的写法
let x;
({x} = {x: 1});

8、延展操作符(Spread operator)
展开数组或者对象。

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];// 将 arr2 中所有元素附加到 arr1 后面并返回
//等同于
var arr4 = arr1.concat(arr2);
 
 
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
 
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
 
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }

9.对象属性简写
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};


function f(x, y) {
  return {x, y};
}

// 等同于
function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

10、promise
见promise 简介
11、新增数组方法

  • Array.from() :方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
let arrayLike = {
   '0': 'a',
   '1': 'b',
   '2': 'c',
   length: 3
};

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

//如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组。
Array.from([1, 2, 3])
// [1, 2, 3]
  • Array.of():用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
Array.of(undefined) // [undefined]
  • copyWithin():在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
// 将从 3 号位直到数组结束的成员(4 和 5),复制到从 0 号位开始的位置,结果覆盖了原来的 1 和 2。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
  • find() 和 findIndex():用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。findIndex返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2
  • fill():使用给定值,填充一个数组。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]
  • entries(),keys() 和 values()
for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"

12、数值的扩展方法

  • Number.isFinite(), Number.isNaN()
    它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false

Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
  • Number.parseInt(), Number.parseFloat()
    ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45

// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
  • Number.isInteger()
Number.isInteger(25) // true
Number.isInteger(25.1) // false
// JavaScript 内部,整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。
Number.isInteger(25.0) // true
  • Number.EPSILON:ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。
Number.EPSILON === Math.pow(2, -52)
// true
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"
  • MIN_SAFE_INTEGER和MAX_SAFE_INTEGER:JavaScript 能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// true
Number.MAX_SAFE_INTEGER === 9007199254740991
// true

Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// true
Number.MIN_SAFE_INTEGER === -9007199254740991
// true
  • Number.isSafeInteger()
Number.isSafeInteger(10);    // true
Number.isSafeInteger(12345678901234567890);  // false
  • Math.trunc(): 用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
// 对于空值和无法截取整数的值,返回NaN
Math.trunc(NaN);      // NaN
Math.trunc('foo');    // NaN
Math.trunc();         // NaN
Math.trunc(undefined) // NaN
二、ES7(ES2016)新特性
  • includes(): 该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它的绝对值大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
  • 指数运算符 :它与 Math.pow(a, b)相同。这个运算符的一个特点是右结合,而不是常见的左结合。多个指数运算符连用时,是从最右边开始计算的。
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512

let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;

你可能感兴趣的:(ES6、ES7常用特性)