ES6常用内容

一、ES6简介
1、发布时间
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
2、ECMAScript 和 JavaScript 的关系
ECMAScript 和 JavaScript 的关系是:前者是后者的规格,后者是前者的一种实现。

二、let和const
1、let命令
ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
2、const命令
const声明一个只读的常量。一旦声明,常量的值就不能改变。这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
3、块级作用域
为什么需要块级作用域:a、内层变量可能会覆盖外层变量;b、用来计数的循环变量泄露为全局变量。
4、let特点
不存在变量提升、暂时性死区、不允许重复声明。
5、ES6声明变量的6种方法
var、function、let、const、import、class

三、解构赋值
1、解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
2、指定默认值

// 数组指定默认值
let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
// 对象指定默认值
var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

四、字符串扩展
1、模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
2、字符串的遍历接口
for…of
3、字符串新增方法
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat():返回一个新字符串,表示将原字符串重复n次。
trimStart() : 消除字符串头部的空格;返回的是新字符串,不会修改原始字符串。
trimEnd():消除尾部的空格;返回的是新字符串,不会修改原始字符串。

五、数值的扩展
1、二进制和八进制的表示
ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。

console.log(0b111110111 === 503); // true
console.log(0o767 === 503); // true

2、扩展方法
Number.isFinite():用来检查一个数值是否为有限的(finite)
Number.isNaN():用来检查一个值是否为NaN
Number.isInteger():用来判断一个数值是否为整数
Math.trunc():用于去除一个数的小数部分,返回整数部分
Math.sign():用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。(a、参数为正数,返回+1;b、参数为负数,返回-1;c、参数为 0,返回0;d、参数为-0,返回-0;e、其他值,返回NaN)

六、函数的扩展
1、函数参数指定默认值

function fun(x, y) {
  y = y || 'World';
  console.log(x, y);
}

fun('Hello') // Hello World
fun('Hello', 'China') // Hello China
fun('Hello', '') // Hello World

2、箭头函数

() => {}

箭头函数有几个使用注意点:
a、函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
b、不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
c、不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

七、数组的扩展
1、扩展运算符
扩展运算符(spread)是三个点(…),使用例子:

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

function push(array, ...items) {
  array.push(...items);
}

function add(x, y) {
  return x + y;
}

const numbers = [4, 38];
add(...numbers) // 42

2、数组扩展方法
Array.of() :用于将一组值,转换为数组

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

find():用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10
// find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组

entries(),keys()和values():用于遍历数组;区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

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"

includes():表示某个数组是否包含给定的值,返回的是一个布尔值

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

flat():用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]

八、对象的扩展
1、遍历对象属性的五种方法
for…in:
for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys(obj):
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames(obj):
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols(obj):
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
Reflect.ownKeys(obj):
Reflect.ownKeys返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
2、对象的新增方法
Object.assign():用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

// Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。
// 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

九、Set数据结构
1、Set数据结构
类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成 Set 数据结构。

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4

2、Set数据结构的属性和方法
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
3、遍历操作
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员

十、Proxy代理
1、概述
概念:Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
参数:Proxy接受两个参数,第一个参数是所要代理的目标对象,第二个参数是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。
2、Proxy实例的方法:
get:用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身,其中最后一个参数可选。

var person = {
  name: "张三"
};

var proxy = new Proxy(person, {
  get: function(target, propKey) {
    if (propKey in target) {
      return target[propKey];
    } else {
      throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
    }
  }
});

proxy.name // "张三"
proxy.age // 抛出一个错误

set:用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

//  假定Person对象有一个age属性,该属性应该是一个不大于 200 的整数,那么可以使用Proxy保证age的属性值符合要求。
let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

// 拦截赋值操作
person.age = 100;
person.age // 100

person.age = 'young' // 报错
person.age = 300 // 报错

3、this问题
在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。

十一、Promise对象
1、简介
Promise 是异步编程的一种解决方案,Promise 是一个对象,从它可以获取异步操作的消息。Promise有两个特点:a、对象的状态不受外界影响;b、一旦状态改变,就不会再变,任何时候都可以得到这个结果。
2、Promise的使用
https://blog.csdn.net/weixin_46777185/article/details/106086409

十二、Iterator 遍历器
1、概念
遍历器(Iterator)是一种接口,为各种不同的数据结构(Array、Object、Map、Set等)提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
2、作用
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for…of循环
3、遍历过程
a、创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
b、第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
c、第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
d、不断调用指针对象的next方法,直到它指向数据结构的结束位置。
注:每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

十三、Generator 函数 (状态机)
1、概念
Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。

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

var hw = helloWorldGenerator();
// 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 }

2、Generator 的next()、throw()、return()方法
next()、throw()、return()这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式:
next():将yield表达式替换成一个值。
throw():将yield表达式替换成一个throw语句。
return():将yield表达式替换成一个return语句。
3、优点
Generator 包含了一个状态信息,即目前是否处于暂停态,所以可以不用外部变量保存状态,这样就更简洁,更安全(状态不会被非法篡改)、更符合函数式编程的思想,在写法上也更优雅。
4、应用场景
异步操作的同步化表达
控制流管理
部署 Iterator 接口
作为数据结构
5、Generator与协程
协程(coroutine)是一种程序运行的方式,可以理解成“协作的线程”或“协作的函数”。协程既可以用单线程实现,也可以用多线程实现。前者是一种特殊的子例程,后者是一种特殊的线程。
a、协程与子例程的差异
传统的“子例程”(subroutine)采用堆栈式“后进先出”的执行方式,只有当调用的子函数完全执行完毕,才会结束执行父函数。协程与其不同,多个线程(单线程情况下,即多个函数)可以并行执行,但是只有一个线程(或函数)处于正在运行的状态,其他线程(或函数)都处于暂停态(suspended),线程(或函数)之间可以交换执行权。也就是说,一个线程(或函数)执行到一半,可以暂停执行,将执行权交给另一个线程(或函数),等到稍后收回执行权的时候,再恢复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。
b、协程与普通线程的差异
协程适合用于多任务运行的环境。在这个意义上,它与普通的线程很相似,都有自己的执行上下文、可以分享全局变量。它们的不同之处在于,同一时间可以有多个线程处于运行状态,但是运行的协程只能有一个,其他协程都处于暂停状态。此外,普通的线程是抢先式的,到底哪个线程优先得到资源,必须由运行环境决定,但是协程是合作式的,执行权由协程自己分配。
6、Generator 与上下文
JavaScript 代码运行时,会产生一个全局的上下文环境(context,又称运行环境),包含了当前所有的变量和对象。然后,执行函数(或块级代码)的时候,又会在当前上下文环境的上层,产生一个函数运行的上下文,变成当前(active)的上下文,由此形成一个上下文环境的堆栈(context stack)。
这个堆栈是“后进先出”的数据结构,最后产生的上下文环境首先执行完成,退出堆栈,然后再执行完成它下层的上下文,直至所有代码执行完成,堆栈清空。
Generator 函数不是这样,它执行产生的上下文环境,一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。

十四、async函数
1、简介
async 函数,它就是 Generator 函数的语法糖。,使得异步操作变得更加方便。
async函数对 Generator 函数的改进,体现在以下四点:a、内置执行器;b、更好的语义;c、更广的适用性;d、返回值是 Promise。
2、基本用法
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

function timeout(ms) {
  return new Promise((resolve) => {
  	// 异步操作,await触发,执行之后再执行await后面的语句
  	console.log('异步操作');
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);  //执行完这个函数之后,再返回来执行下面的语句
  console.log(value);
}

asyncPrint('hello world', 1000);
// 先输出 '异步操作',然后 1000毫秒后输出 'hello world'

3、语法
a、返回 Promise 对象:
async函数返回一个 Promise 对象;async函数内部return语句返回的值,会成为then方法回调函数的参数。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"
// 函数f()内部return命令返回的值,会被then方法回调函数接收到。

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log(v),
  e => console.log(e)
)
// Error: 出错了

b、Promise 对象的状态变化
async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
4、await命令
await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。

十五、Class类
1、简介
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。ES6 的类,完全可以看作构造函数的另一种写法。
class使用的时候,不存在变量提升,直接对类使用new命令。需要注意的是:类的所有方法都定义在类的prototype属性上面,并且类的内部所有定义的方法,都是不可枚举的。
2、Class类的继承
Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class Point {
	constructor(){}
	toString(){
		// …………………………
	}
}
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); 
    // 调用父类的toString()
  }
}

// constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

3、super关键字
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。

class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() // A
new B() // B
// 上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。
//注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例,因此super()在这里相当于A.prototype.constructor.call(this)。

第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值