ES6基础

1、let和const命令

1.1、let命令

所声明的变量,只在let命令所在的代码块内有效。

for循环的计数器,就很合适使用let命令。

var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

let不允许在相同作用域内,重复声明同一个变量。

let实际上为 JavaScript 新增了块级作用域。

避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句,let f = function(){}

1.2、const命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const的作用域与let命令相同:只在声明所在的块级作用域内有效。

const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

2、解构赋值

2.1、数组的解构赋值

从数组和对象中提取值,对变量进行赋值

let [a, b, c] = [1, 2, 3];可以从数组中提取值,按照对应位置,对变量赋值,如果解构不成功,变量的值就等于undefined

解构赋值允许指定默认值:let [foo = true] = []

2.2、对象的解构赋值

let { foo, bar } = { foo: “aaa”, bar: “bbb” }

数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值

let { foo: foo, bar: bar } = { foo: “aaa”, bar: “bbb” }

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。如果解构失败,变量的值等于undefined

对象的解构也可以指定默认值:var {x = 3} = {}

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量:let { log, sin, cos } = Math

2.3、字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象:const [a, b, c, d, e] = ‘hello’

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值:let {length : len} = ‘hello’

2.4、数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象:let {toString: s} = 123;
s === Number.prototype.toString // true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。

2.5、结构赋值的用途

交换变量的值

从函数返回多个值

函数参数的定义

提取 JSON 数据

函数参数的默认值

遍历 Map 结构

输入模块的指定方法:const { SourceMapConsumer, SourceNode } = require(“source-map”);

3、字符串扩展

3.1、字符的unicode扩展

JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点,"\u0061"// “a”

这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示

ES6只要将码点放入大括号,就能正确解读该字符,"\u{41}\u{42}\u{43}"// “ABC”

JavaScript 共有 6 种方法可以表示一个字符:

  • ‘\z’ === ‘z’ // true
  • ‘\172’ === ‘z’ // true
  • ‘\x7A’ === ‘z’ // true
  • ‘\u007A’ === ‘z’ // true
  • ‘\u{7A}’ === ‘z’ // true

3.2、codePointAt()

JavaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。

ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。

codePointAt方法的参数,是字符在字符串中的位置(从 0 开始)。

codePointAt方法会正确返回32位的UTF-16字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同。

codePointAt方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString方法转换一下。

3.3、String.fromCodePoint()

ES6 提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符

String.fromCodePoint(0x20BB7) // “?”

3.4、字符串的遍历器接口

ES6为字符串添加了遍历器接口,使得字符串可以被for…of循环遍历。

除了遍历字符串,for…of…循环遍历的最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。

3.5、at()

at方法,可以识别 Unicode 编号大于0xFFFF的字符,返回正确的字符。

3.6、normalize()

normalize()方法,用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。

‘\u01D1’.normalize() === ‘\u004F\u030C’.normalize() //true

3.7、includes()、startsWith()、endsWith()

includes():返回布尔值,表示是否找到了参数字符串。

startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

这三个方法都支持第二个参数,表示开始搜索的位置。

3.8、repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次,'x'.repeat(3)//"xxx"

3.9、padStart()、padEnd()

padStart()用于头部补全

padEnd()用于尾部补全

padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。

‘x’.padStart(5, ‘ab’) // ‘ababx’

3.10、模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

模板字符串中嵌入变量,需要将变量名写在${}之中。

let name = “Bob”, time = “today”; Hello ${name}, how are you ${time}?

3.11、模板编译

该模板使用<%...%>放置 JavaScript 代码,使用<%= ... %>输出 JavaScript 表达式

3.12、标签模板

模板字符串可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串,alert `123` 等同于 alert(123)

4、数值的扩展

4.1、二进制和八进制

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

0b111110111 === 503 // true

0o767 === 503 // true

4.2、Number.isFinite()与Number.isNaN()

Number.isFinite()用来检查一个数值是否为有限的(finite)。

Number.isNaN()用来检查一个值是否为NaN。

4.3、Number.parseInt()与Number.parseFloat()

ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。

这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。

4.4、Number.isInteger()

用来判断一个值是否为整数。需要注意的是,在 JavaScript 内部,整数和浮点数是同样的储存方法,所以 3 和 3.0 被视为同一个值。

4.5、Number.EPSILON

Number.EPSILON实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了

4.6、安全整数和Number.isSafeInteger()

引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。

4.7、Math对象的扩展

Math.trunc(),Math.trunc方法用于去除一个数的小数部分,返回整数部分。

Math.sign():

  • 参数为正数,返回+1
  • 参数为负数,返回-1
  • 参数为 0,返回0
  • 参数为-0,返回-0
  • 其他值,返回NaN

Math.cbrt(),Math.cbrt方法用于计算一个数的立方根。

Math.imul(),Math.imul方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。

Math.fround(),Math.fround 方法返回一个数的单精度浮点数形式。

Math.hypot(),Math.hypot方法返回所有参数的平方和的平方根。

5、函数的扩展

5.1、函数参数的默认值

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = ‘World’) {console.log(x, y);}

通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。

5.2、rest参数

ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

函数的length属性,不包括 rest 参数。

5.3、严格模式

只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

5.4、name属性

函数的name属性,返回该函数的函数名。

5.5、箭头函数

ES6 允许使用“箭头”(=>)定义函数。

var f = v => v;

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

this对象的指向是可变的,但是在箭头函数中,它是固定的。

5.6、双冒号运算符

函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

5.7、尾调用优化

某个函数的最后一步是调用另一个函数

6、数组的扩展

6.1、扩展运算符

扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

该运算符主要用于函数调用。

扩展运算符的运用:

  • 复制数组
  • 合并数组
  • 与解构赋值结合
  • 将字符串转为真正的数组
  • 实现了 Iterator 接口的对象
  • Map 和 Set 结构,Generator 函数

6.2、Array.from方法

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

6.3、Array.of方法

Array.of方法用于将一组值,转换为数组

6.4、copyWithin方法

在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组

Array.prototype.copyWithin(target, start = 0, end = this.length)

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

6.5、find()和findIndex()

find()方法,用于找出第一个符合条件的数组成员

findIndex()返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

6.6、fill()

fill方法使用给定值,填充一个数组。

fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

6.7、entries()、keys()、values()

entries(),对键值对的遍历。

keys(),对键名的遍历

values(),对键值的遍历

6.8、includes()

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

6.9、数组的空位

数组的空位指,数组的某一个位置没有任何值

7、对象的扩展

7.1、属性的简介表示法

ES6 允许直接写入变量和函数,作为对象的属性和方法

7.2、属性名表达式

ES6 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内。

7.3、方法的name属性

函数的name属性,返回函数名。对象方法也是函数,因此也有name属性

如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。

7.4、Object.is()

它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

7.5、Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

7.6、属性的遍历

for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)

Object.keys()返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

7.7、super关键字

指向当前对象的原型对象

7.8、Object.keys()

返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。

7.9、Object.values()

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。

7.10、Object.entries()

Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。

7.11、对象的扩展运算符

扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

8、Symbol

8.1、ES6 引入的一种新的原始数据类型Symbol,表示独一无二的值

8.2、Symbol 值通过Symbol函数生成

let s = Symbol();

8.3、作为属性名的Symbol

Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性

Symbol 值作为对象属性名时,不能用点运算符。

在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

8.4、消除魔术字符串

魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。

8.5、Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

8.6、Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

8.7、Symbol.for方法接受一个字符串作为参数,使用同一个 Symbol 值

8.8、Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key

Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key。

9、Set、Map

9.1、Set

它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set 函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

去除数组重复成员的方法,[…new Set(array)]

Array.from方法可以将 Set 结构转为数组。

set操作方法:

  • add(value)
  • delete(value)
  • has(value)
  • clear()

set遍历方法:

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

数组的map和filter方法也可以间接用于 Set 了:

  • set = new Set([…set].map(x => x * 2));
  • set = new Set([…set].filter(x => (x % 2) == 0))

9.2、Map

它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数。

属性,size属性返回 Map 结构的成员总数。

操作方法:

  • set(key, value),如果key已经有值,则键值会被更新,否则就新生成该键。
  • get(key),get方法读取key对应的键值,如果找不到key,返回undefined。
  • has(key),has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
  • delete(key),delete方法删除某个键,返回true。如果删除失败,返回false。
  • clear(),clear方法清除所有成员,没有返回值。

遍历方法:

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。

需要特别注意的是,Map 的遍历顺序就是插入顺序。

Map 结构转为数组结构,比较快速的方法是使用扩展运算符(…),[…map.keys()]

10、Proxy

10.1、概述

修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

var proxy = new Proxy(target, handler);

10.2、proxy实例方法

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(即this关键字指向的那个对象),其中最后一个参数可选。

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

apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。

has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。

construct方法用于拦截new命令,下面是拦截对象的写法。

deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。

defineProperty方法拦截了Object.defineProperty操作。

getOwnPropertyDescriptor方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined。

getPrototypeOf方法主要用来拦截获取对象原型。

isExtensible方法拦截Object.isExtensible操作。

ownKeys方法用来拦截对象自身属性的读取操作。

preventExtensions方法拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。

setPrototypeOf方法主要用来拦截Object.setPrototypeOf方法。

10.3、Proxy.revocable

返回一个可取消的 Proxy 实例

10.4、this

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

11、Reflect

11.1、Reflect的设计目的

将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上

修改某些Object方法的返回结果,让其变得更合理

让Object操作都变成函数行为。

Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

11.2、静态方法

Reflect.get方法查找并返回target对象的name属性,如果没有该属性,则返回undefined。

Reflect.set方法设置target对象的name属性等于value

Reflect.has方法对应name in obj里面的in运算符。

Reflect.deleteProperty方法等同于delete obj[name],用于删除对象的属性。

Reflect.construct方法等同于new target(…args),这提供了一种不使用new,来调用构造函数的方法。

Reflect.getPrototypeOf方法用于读取对象的__proto__属性,对应Object.getPrototypeOf(obj)。

Reflect.setPrototypeOf方法用于设置对象的__proto__属性,返回第一个参数对象,对应Object.setPrototypeOf(obj, newProto)。

Reflect.apply方法等同于Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数。

Reflect.defineProperty方法基本等同于Object.defineProperty,用来为对象定义属性。

Reflect.getOwnPropertyDescriptor基本等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会替代掉后者。

Reflect.isExtensible方法对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。

Reflect.preventExtensions对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。

12、Promise对象

12.1、promise含义

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果

Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点:

  • 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
  • Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。

12.2、基本用法

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

12.3、Promise.prototype.then()

Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

12.4、Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

12.5、Promise.all()

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

12.6、Promise.race()

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

12.7、Promise.resolve()

有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。

12.8、Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。

13、Iterator和for of循环

13.1、Iterator(遍历器)的概念

遍历器(Iterator),它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费。

13.2、默认 Iterator 接口

一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。

原生具备 Iterator 接口的数据结构如下:Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象

13.3、调用 Iterator 接口的场合

对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法。

扩展运算符(…)也会调用默认的 Iterator 接口。

yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。

13.4、字符串的 Iterator 接口

字符串是一个类似数组的对象,也原生具有 Iterator 接口。

13.5、Iterator 接口与 Generator 函数

遍历器对象的 return(),throw()

13.6、for...of 循环

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。

14、Generator函数的语法

14.1、简介

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。

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

Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

14.2、next 方法的参数

yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

14.3、for...of 循环

for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。

14.4、Generator.prototype.throw()

Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。

14.5、Generator.prototype.return()

Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。

15、Generator函数的异步运用

15.1、基本概念

“异步”,简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。

连续的执行就叫做同步。连续执行,不能插入其他任务

回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。

Promise对象是一种新的写法,允许将回调函数的嵌套,改成链式调用。

15.2、Generator函数

整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。

16、Async函数

16.1、含义

async函数它就是 Generator 函数的语法糖

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await

async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

async函数对 Generator 函数的改进,体现在以下四点:

  • async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
  • async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
  • async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
  • async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

16.2、基本用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

16.3、语法

async函数返回一个 Promise 对象。

async函数内部return语句返回的值,会成为then方法回调函数的参数。

async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。

16.4、async 函数的实现原理

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

17、Class的基本语法

17.1、简介

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

17.2、严格模式

类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。

17.3、constructor 方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

17.4、类的实例对象

实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。

17.5、Class 表达式

与函数一样,类也可以使用表达式的形式定义。

17.6、不存在变量提升

17.7、私有方法和私有属性

17.8、this 的指向

类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。

17.9、name 属性

name属性总是返回紧跟在class关键字后面的类名。

17.10、Class 的取值函数(getter)和存值函数(setter)

与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

17.11、Class 的 Generator 方法

如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。

17.12、Class 的静态方法

如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

18、Class继承

18.1、简介

Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。

18.2、Object.getPrototypeOf()

Object.getPrototypeOf方法可以用来从子类上获取父类。

18.3、super 关键字

super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。

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

18.4、类的 prototype 属性和__proto__属性

子类的__proto__属性,表示构造函数的继承,总是指向父类。

子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

19、Decorator

19.1、类的修饰

修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类。

19.2、方法的修饰

19.3、为什么修饰器不能用于函数?

修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。

20、Module的语法

20.1、概述

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

20.2、严格模式

ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。

20.3、export 命令

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

export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。export {m};

export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

export命令可以出现在模块的任何位置,只要处于模块顶层就可以。

20.4、import 命令

import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块对外接口的名称相同。

import命令具有提升效果,会提升到整个模块的头部,首先执行。

20.5、模块的整体加载

除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。

20.6、export default 命令

export default命令,为模块指定默认输出。

import命令可以为该匿名函数指定任意名字

这时import命令后面,不使用大括号。

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

20.7、export 与 import 的复合写法

如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起

20.8、跨模块常量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值