ES6常用内容

「爱情、让人受尽委屈。」 2022-11-24 14:10 290阅读 0赞

一、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、指定默认值

  1. // 数组指定默认值
  2. let [foo = true] = [];
  3. foo // true
  4. let [x, y = 'b'] = ['a']; // x='a', y='b'
  5. let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
  6. // 对象指定默认值
  7. var { x = 3} = { };
  8. x // 3
  9. var { x, y = 5} = { x: 1};
  10. x // 1
  11. y // 5
  12. var { x: y = 3} = { };
  13. y // 3
  14. var { x: y = 3} = { x: 5};
  15. y // 5
  16. var { message: msg = 'Something went wrong' } = { };
  17. msg // "Something went wrong"

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

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

  1. console.log(0b111110111 === 503); // true
  2. 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、函数参数指定默认值

  1. function fun(x, y) {
  2. y = y || 'World';
  3. console.log(x, y);
  4. }
  5. fun('Hello') // Hello World
  6. fun('Hello', 'China') // Hello China
  7. fun('Hello', '') // Hello World

2、箭头函数

  1. () => { }

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

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

  1. console.log(...[1, 2, 3])
  2. // 1 2 3
  3. console.log(1, ...[2, 3, 4], 5)
  4. // 1 2 3 4 5
  5. function push(array, ...items) {
  6. array.push(...items);
  7. }
  8. function add(x, y) {
  9. return x + y;
  10. }
  11. const numbers = [4, 38];
  12. add(...numbers) // 42

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

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

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

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

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

  1. for (let index of ['a', 'b'].keys()) {
  2. console.log(index);
  3. }
  4. // 0
  5. // 1
  6. for (let elem of ['a', 'b'].values()) {
  7. console.log(elem);
  8. }
  9. // 'a'
  10. // 'b'
  11. for (let [index, elem] of ['a', 'b'].entries()) {
  12. console.log(index, elem);
  13. }
  14. // 0 "a"
  15. // 1 "b"

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

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

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

  1. [1, 2, [3, [4, 5]]].flat()
  2. // [1, 2, 3, [4, 5]]
  3. [1, 2, [3, [4, 5]]].flat(2)
  4. // [1, 2, 3, 4, 5]
  5. [1, [2, [3]]].flat(Infinity)
  6. // [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)

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

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

  1. const s = new Set();
  2. [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
  3. for (let i of s) {
  4. console.log(i);
  5. }
  6. // 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 实例本身,其中最后一个参数可选。

  1. var person = {
  2. name: "张三"
  3. };
  4. var proxy = new Proxy(person, {
  5. get: function(target, propKey) {
  6. if (propKey in target) {
  7. return target[propKey];
  8. } else {
  9. throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
  10. }
  11. }
  12. });
  13. proxy.name // "张三"
  14. proxy.age // 抛出一个错误

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

  1. // 假定Person对象有一个age属性,该属性应该是一个不大于 200 的整数,那么可以使用Proxy保证age的属性值符合要求。
  2. let validator = {
  3. set: function(obj, prop, value) {
  4. if (prop === 'age') {
  5. if (!Number.isInteger(value)) {
  6. throw new TypeError('The age is not an integer');
  7. }
  8. if (value > 200) {
  9. throw new RangeError('The age seems invalid');
  10. }
  11. }
  12. // 对于满足条件的 age 属性以及其他属性,直接保存
  13. obj[prop] = value;
  14. }
  15. };
  16. let person = new Proxy({ }, validator);
  17. // 拦截赋值操作
  18. person.age = 100;
  19. person.age // 100
  20. person.age = 'young' // 报错
  21. 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属性是一个布尔值,表示遍历是否结束。

  1. function makeIterator(array) {
  2. var nextIndex = 0;
  3. return {
  4. next: function() {
  5. return nextIndex < array.length ?
  6. {value: array[nextIndex++], done: false} :
  7. {value: undefined, done: true};
  8. }
  9. };
  10. }
  11. var it = makeIterator(['a', 'b']);
  12. it.next() // { value: "a", done: false }
  13. it.next() // { value: "b", done: false }
  14. it.next() // { value: undefined, done: true }

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

  1. function* helloWorldGenerator() {
  2. yield 'hello';
  3. yield 'world';
  4. return 'ending';
  5. }
  6. var hw = helloWorldGenerator();
  7. // Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象;
  8. // 下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
  9. hw.next() // { value: 'hello', done: false }
  10. hw.next() // { value: 'world', done: false }
  11. hw.next() // { value: 'ending', done: true }
  12. 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就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

  1. function timeout(ms) {
  2. return new Promise((resolve) => {
  3. // 异步操作,await触发,执行之后再执行await后面的语句
  4. console.log('异步操作');
  5. setTimeout(resolve, ms);
  6. });
  7. }
  8. async function asyncPrint(value, ms) {
  9. await timeout(ms); //执行完这个函数之后,再返回来执行下面的语句
  10. console.log(value);
  11. }
  12. asyncPrint('hello world', 1000);
  13. // 先输出 '异步操作',然后 1000毫秒后输出 'hello world'

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

  1. async function f() {
  2. return 'hello world';
  3. }
  4. f().then(v => console.log(v))
  5. // "hello world"
  6. // 函数f()内部return命令返回的值,会被then方法回调函数接收到。

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

  1. async function f() {
  2. throw new Error('出错了');
  3. }
  4. f().then(
  5. v => console.log(v),
  6. e => console.log(e)
  7. )
  8. // 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 的通过修改原型链实现继承,要清晰和方便很多。

  1. class Point {
  2. constructor(){ }
  3. toString(){
  4. // …………………………
  5. }
  6. }
  7. class ColorPoint extends Point {
  8. constructor(x, y, color) {
  9. super(x, y); // 调用父类的constructor(x, y)
  10. this.color = color;
  11. }
  12. toString() {
  13. return this.color + ' ' + super.toString();
  14. // 调用父类的toString()
  15. }
  16. }
  17. // constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

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

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

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

  1. class A {
  2. p() {
  3. return 2;
  4. }
  5. }
  6. class B extends A {
  7. constructor() {
  8. super();
  9. console.log(super.p()); // 2
  10. }
  11. }
  12. let b = new B();

发表评论

表情:
评论列表 (有 0 条评论,290人围观)

还没有评论,来说两句吧...

相关阅读

    相关 ES6新特性

    ES6改动很大,可以简单分为四类 1、解决原有语法的缺陷和不足 例如:let,const 2、对原有语法进行增强 解构、扩展、模板字符串 3、新增对象、全新

    相关 ES6新增内容

    1、map、filter和reduce的区别 map 作用是生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入到新的数组中。map 的回调函数接受三个参数,分

    相关 ES6语法

    后天就要交大论文绪论的,现在居然还在这写博客,YNB!   聊正事!什么是ES,ES就是ECMA Script,Javascript的语言标准,我们今天具体说下 一.

    相关 ES6语法

    [转载文章地址][Link 1] var 之前,js定义变量只有一个关键字:var var有一个问题,就是定义的变量有时会莫名奇妙的成为全局变量。 例如这样