自己的学习记录,有什么不对的望指正。
基础要点
let 与 const
(1)不存在变量提升;如果使用function声明变量,还是会像var那样变量提升
(2)const 基本类型的话,主要是保持指向内存的值不能改变;复合类型的话,主要是保持指向不能改变。可以使用 Object.freeze 冻结
js函数重载
传入不同的参数,得到不一样的结果。(进行参数的判断,进行不一样的操作)
数据结构
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set
call
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
String
str.match(RegExp) 方法检索将字符串与正则表达式匹配的结果 RegExp有g返回Array,没有则返回第一个完全匹配及其相关捕获组。
str.substring(indexStart,indexEnd) 方法返回stringstart和end索引之间或字符串末尾的部分。 'Mozilla'.substring(1, 3) //oz
str.search(RegExp) 方法执行搜索以查找正则表达式与此String对象之间的匹配项 返回索引
RegExp
RegExp.exec(str) //方法用于检索字符串中的正则表达式的匹配。 /s/g.exec('string') //s
RegExp.test() //方法用于检测一个字符串是否匹配某个模式。返回 true 或 false
Number
Number.parseInt(number) //解析数字,并返回一个整数
Number.parseFloat(number) //解析数字,并返回一个浮点数
Number.isInteger(number) //解析数字,判断是否为整数 Number.isInteger(25.0) // true Number.isInteger(3.0000000000000002) // true
Math
Math.min(...arr) //返回零个或更多个数值的最小值。如果任一参数不能转换为数值,则返回NaN
Math.max(...arr) //返回一组数中的最大值。如果任一参数不能转换为数值,则返回NaN
Math.pow(x,y) //方法可返回 x 的 y 次幂的值
Math.abs(number) //指定数字 number 的绝对值
Math.round(number) //数字四舍五入
Math.ceil(number) //向上取整
Math.floor(number) //向下取整
Math.random() //随机数
Math.trunc(number) //去除一个数的小数部分,返回整数部分;对于非数值,Math.trunc内部使用Number方法将其先转为数值 true:1,false:0;null:0
Math.abrc(number) //用于计算一个数的立方根,对于非数值,Math.cbrt方法内部也是先使用Number方法将其转为数值 Math.cbrt('8') // 2
Math.sign(number) //方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值:
参数为正数,返回+1;
参数为负数,返回-1;
参数为 0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
Array
forEach循环,break命令或return命令都不能奏效
Array静态方法.:
Array.from(set,mapFn,thisArg) 从一个类似数组(有length属性)或可迭代(iterable)对象创建一个新的,浅拷贝的数组实例。
参数:
set 一个类似数组(有length属性)或可迭代(iterable)对象
mapFn 类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组
thisArg 绑定回调函数的this对象
Array.isArray(arr) 用于判断数组
Array.of(...value) 用于将一组值,转换为数组
Array实例方法:
arr.copyWithin(target,start,end) 指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组 [1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5]
参数:
target(必需):从该位置开始替换数据。如果为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
arr.find(fn(item,index,arr),thisArg) 返回数组中满足提供的回调函数为true的第一个元素的值。否则返回 undefined。
参数:
thisArg 绑定回调函数的this对象
arr.findIndex(fn(item,index,arr),thisArg) 返回数组中满足提供的回调函数为true的第一个元素的索引。否则返回-1
arr.fill(value,start,end) 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
参数:
value 用来填充数组元素的值。
start 可选 起始索引,默认值为0。
end 可选 终止索引,默认值为 this.length。
arr.includes(value,target) 返回一个布尔值,表示某个数组是否包含给定的值
参数:
value 需要查找的元素值
target 搜索的起始位置,第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度,则会重置为从0开始。
arr.flat(depth) 会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。如果原数组有空位,flat()方法会跳过空位。
参数:
depth 指定要提取嵌套数组的结构深度,默认值为 1。
arr.flatMap(mapFn,thisArg) 对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
参数:
mapFn 类似于数组的map方法,用来对每个元素进行处理。
flatMap()只能展开一层数组
thisArg 绑定回调函数的this对象
arr.sort(fn(firstEl,secondEl)) 用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
参数:
fn 用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
firstEl 第一个用于比较的元素。
secondEl 第二个用于比较的元素。
遍历方法:
arr.entries() 返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
arr.keys() 返回一个包含数组中每个索引键的Array Iterator对象。
arr.values() 返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值
Object
对象属性特性.:
writeable(可写): 表示是否能修改属性的值。
enumerable(可枚举): 表示能否通过for-in循环返回属性,代表属性是否可枚举
configurable(可配置):是否能通过delete删除属性从而重新定义属性,能否修改属性的三个特性,或者能否把属性修改为访问器属性,直接在对象上定义属性。
Object静态方法.:
Object.is(value1,value2) 方法确定两个值是否相同
Object.freeze(obj) 冻结对象
Object.create(obj) 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Object.assign(target,source1,source2) 方法用于对象的合并,将源对象(source1,source2)的所有可枚举属性,复制到目标对象(target)
注意:
只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)
Object.defineProperty(obj,prop,descriptor) 直接在对象上定义新属性,或修改对象上的现有属性,然后返回对象
参数:
obj 要在其上定义属性的对象。
prop 要定义或修改的属性的名称或名称。
descriptor 定义或修改的属性的描述符。
Object.defineProperties(obj,descriptor) 直接在对象上定义新属性或修改现有属性,并返回该对象。
Object.keys(obj) 方法会返回一个由一个给定对象的自身可枚举属性组成的数组。
Object.values(obj) 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
注意:
Object.values会过滤属性名为 Symbol 值的属性
Object.entries() 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
注意:
如果原对象的属性名是一个 Symbol 值,该属性会被忽略
Object.entries方法的另一个用处是,将对象转为真正的Map结构
Object.fromEntries() 是Object.entries()的逆操作,用于将一个键值对数组转为对象。
演示:
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
获取属性
Object.getOwnPropertyNames(obj) 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
Object.getOwnPropertySymbols(obj) 方法返回一个给定对象自身的所有 Symbol 属性的数组
Object.getOwnPropertyDescriptor(obj,key) 方法返回指定对象上一个自有属性(非继承属性)对应的属性描述符。
Object.getOwnPropertyDescriptors(obj) 返回指定对象所有自身属性(非继承属性)的描述对象
查找属性
obj.hasOwnProperty(key) 方法会返回一个布尔值,指示对象自身属性(非继承)中是否具有指定的属性(也就是,是否有指定的键)
更改对象属性描述符
Object.preventExtensions(obj) 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
获取对象属性描述符
Object.isExtensible(obj) 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
获取原型
Object.getPrototypeOf(parent) 方法返回指定对象(parent)的原型
设置原型
Object.setPrototypeOf(obj, prototype) 方法设置一个指定的对象(obj)的原型 ( 即, 内部[[Prototype]]属性)到另一个对象(prototype)或 null。
判断对象原型链
Parent.prototype.isPrototypeOf(parent) 方法用于测试一个对象(Parent)是否存在于另一个对象(parent)的原型链上
说明:
Parent 构造函数,parent 实例对象
parent instanceof Parent 用于检测构造函数(Parent)的 prototype 属性是否出现在某个实例对象(parent)的原型链上。
Object实例方法.:
obj.propertyIsEnumerable(key) 方法返回一个布尔值,表示指定的属性是否可枚举
扩展
this关键字总是指向函数所在的当前对象
super指向当前对象的原型对象,只能用在对象的方法之中,用在其他地方都会报错(慎用)
扩展运算符的解构赋值,只能读取对象o自身的属性,原型里面的属性是拿不到的 //{ ...obj } = o
相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。
Object.assign方法实行的是浅拷贝,而不是深拷贝
Set
介绍
ES6 提供了新的数据结构 Set。它类似于数组.,但是成员的值都是唯一的.,没有重复的值.,注意键名就是键值.
Set 加入值的时候,不会发生类型转换.,所以5和"5"是两个不同的值,两个NaN是相等的。两个空对象(引用地址不同)总是不相等的
实例化
let set = new Set([1,2,3])
属性:
set.size 获取成员总数
操作方法:
set.add(value) 添加某个值,返回 Set 结构本身。
set.delete(value) 删除某个值,返回一个布尔值,表示删除是否成功。
set.has(value) 返回一个布尔值,表示该值是否为Set的成员。
set.clear() 清除所有成员,没有返回值。
遍历方法:
set.keys() 返回键名的遍历器 for (let item of set.keys())
set.values() 返回键值的遍历器 for (let item of set.values()) 默认是 values for (let item of set)
set.entries() 返回键值对的遍历器 for (let item of set.entries())
set.forEach() 使用回调函数遍历每个成员 set.forEach((value, key) => console.log(key + ' : ' + value))
Set 结构转为数组结构
[...set] //[1,2,3] Array.from(set) //[1,2,3]
去除数组的重复成员
[...new Set(array)] [...new Set('ababbc')].join('') Array.from(new Set(array)
weakSet
介绍
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象.,而不能是其他类型的值. new WeakSet([[1, 2], [3, 4]]) new WeakSet([{a:1},{b:2}])
其次,WeakSet 中的对象都是弱引用.,即垃圾回收机制不考虑 WeakSet 对一个对象的引用
垃圾回收机制依赖引用计数,WeakSet 里面的引用,都不计入垃圾回收机制。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。
垃圾回收机制对对象进行回收释放,它在 WeakSet 里面的引用就会自动消失
垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历.,没有size属性.,无法清空.,即不支持clear方法
WeakSet 不可遍历.,因为成员都是弱引用.,随时可能消失.
实例化
let ws = new WeakSet();
方法:
ws.add(value) 向 ws 实例添加一个新成员。
ws.delete(value) 清除 ws 实例的指定成员。
ws.has(value) 返回一个布尔值,表示某个值是否在 WeakSet 实例之中
Map
介绍
Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
如果你需要“键值对”的数据结构,Map 比 Object 更合适
只有对同一个对象的引用,Map 结构才将其视为同一个键.。
0和-0是一个键,布尔值true和字符串true则是两个不同的键,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。
实例化
Map 接受一个数组作为参数。该数组的成员是一个个表示键值对的数组
const map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
上面代码在新建 Map 实例时,就指定了两个键1和2
属性:
map.size 返回 Map 结构的成员总数
操作方法:
map.set(key, value) 设置键名key对应的键值为value,返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键
map.get(key) 读取key对应的键值,如果找不到key,返回undefined
map.has(key) 返回一个布尔值,表示某个键是否在当前 Map 对象之中
map.delete(key) 删除某个键,返回true。如果删除失败,返回false
map.clear() 清除所有成员,没有返回值
遍历方法:
map.keys() //返回键名的遍历器。for (let key of map.keys())
map.values() //返回键值的遍历器。for (let value of map.values())
map.entries() //返回所有成员的遍历器。
说明
1、for (let item of map.entries()) item[0]=键, item[1]=值
2、for (let [key,value] of map.entries()) key=键, value=值
3、默认 遍历器接口(Symbol.iterator属性),就是entries方法 =>for (let [key, value] of map)
map.forEach() //遍历 Map 的所有成员。 与数组的forEach方法类似,也可以实现遍历,可以接受第二个参数,用来绑定this
Map 结构转为数组结构
[...map.keys()]
// [1, 2, 3]
[...map.values()]
// ['one', 'two', 'three']
[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]
[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
WeakMapMath
介绍
WeakMap结构与Map结构类似,也是用于生成键值对的集合。
WeakMap与Map的区别有两点:
首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。例如:存储DOM 节点作为键名存入该实例,并将一些附加信息作为键值,有助于防止内存泄漏
注意: WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。
垃圾回收机制何时运行是不可预测的,因此 没有遍历操作,没有size属性,无法清空,即不支持clear方法。
方法:
map.set(key, value) 设置键名key对应的键值value,返回整个WeakMap结构。如果key已经有值,则键值会更新,否则就新生成该键
map.get(key) 读取key对应的键值,如果找不到key,返回undefined
map.has(key) 返回一个布尔值,表示某个键是否在当前 Map 对象之中
map.delete(key) 删除某个键,返回true。如果删除失败,返回false
Proxy
介绍
Proxy 可以理解成,在目标对象之前架设一层 “拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
--方法.:
实例化
正常实例化
let proxy = new Proxy(target,handler)
参数:
target参数表示所要拦截的目标对象。
handler参数也是一个对象,用来定制拦截行为。
带取消的实例化
2. let {proxy, revoke} = Proxy.revocable(target, handler)
说明:
proxy属性是Proxy的实例对象
revoke属性是一个函数,可以取消Proxy实例
注意:
一旦proxy实例 代理target对象,后者内部的this就是指向proxy,而不是target
handler对象:
参数: target:目标对象, propKey:属性名、键 ,value:属性值, receiver:当前上下文(this)
get(target, propKey, receiver) 拦截对象属性的读取,比如proxy.foo和proxy['foo']。
注意.:一个属性 不可配置且不可写,则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错
set(target, propKey, value, receiver) 拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
注意:
如果目标对象自身的某个属性,不可写且不可配置.,那么set方法将不起作用
严格模式下.,set代理如果没有 返回true.,就会报错
has(target, propKey) 拦截propKey in proxy的操作,返回一个布尔值。
注意:
原对象不可配置或者禁止扩展,这时has拦截会报错 //Object.preventExtensions(target);
deleteProperty(target, propKey) 拦截delete proxy[propKey]的操作,返回一个布尔值。
注意:
目标对象自身的不可配置(configurable)的属性,不能被deleteProperty方法删除,否则报错
deleteProperty方法中抛出错误或者返回false,当前属性就无法被delete命令删除
ownKeys(target) 拦截对象自身属性的读取操作。返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
拦截操作:
Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环
getOwnPropertyDescriptor(target, propKey) 拦截属性描述对象,Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc) 返回一个布尔值。
参数:
propDesc:要定义或修改的属性描述符
拦截操作:
Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs)
注意:
如果 目标对象不可扩展.(non-extensible),则defineProperty不能增加目标对象上不存在的属性,否则会报错。
另外,如果目标对象的某个属性 不可写(writable)或不可配置(configurable),则defineProperty方法 不得改变这两个设置。
preventExtensions(target) 拦截Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf(target) 拦截不可扩展的对象,Object.getPrototypeOf(proxy),返回一个对象。
isExtensible(target) 主要用来拦截获取对象原型,是否是可扩展的,Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf(target, proto) 拦截设置对象原型,Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
注意:该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展(non-extensible),setPrototypeOf方法不得改变目标对象的原型
apply(target, object, args) 拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
参数:
object 目标对象的上下文对象(this)
args 目标对象的参数数组
construct(target, args,newTarget) 拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
参数:
args 构造函数的参数对象
newTarget:创造实例对象时,new命令作用的构造函数(下面例子的p)
实例:
var p = new Proxy(function () {}, {
construct: function(target, args) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 };
}
});
(new p(1)).value
注意.:construct方法返回的必须是一个 对象,否则会报错。
Reflect
介绍
(1)将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法
(2)修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
Reflect对象静态方法:
大部分与Object对象的同名方法的作用都是相同的,而且它与Proxy对象的方法是一一对应的。
参数:target:目标对象,key:属性名、键,value:属性值,receiver:当前上下文(this)
Reflect.get(target, key, receiver) 查找并返回target对象的key属性,如果没有该属性,则返回undefined。
注意:
如果第一个参数不是对象,Reflect.get方法会报错
Reflect.set(target, key, value, receiver) 设置target对象的key属性等于value
注意:
如果 Proxy对象和 Reflect对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为,如果 Reflect.set 传入了receiver,那么会触发 Proxy.defineProperty拦截
Reflect.has(target, key) 对应name in obj里面的in运算符
Reflect.apply(target, thisArg, args) 改变this指向,使thisArg指向target ,args数组,传值
Reflect.construct(fn, args) 等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法。
注意:
如果 Reflect.construct() 方法的第一个参数不是函数,会报错
Reflect.defineProperty(target, key, desc) 基本等同于Object.defineProperty
参数:
desc:要定义或修改的属性描述符
注意:
如果Reflect.defineProperty的第一个参数不是对象,就会抛出错误
Reflect.deleteProperty(target, key) 等同于delete obj[name],用于删除对象的属性
Reflect.ownKeys(target) 用于返回包含对象的所有属性的数组,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和
Reflect.isExtensible(target) 对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展
Reflect.preventExtensions(target) 对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功
Reflect.getOwnPropertyDescriptor(target, key) 等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会替代掉后者
Reflect.getPrototypeOf(target) 读取对象的__proto__属性,对应Object.getPrototypeOf(obj)。
Reflect.setPrototypeOf(target, prototype) 设置目标对象的原型(prototype),对应Object.setPrototypeOf(obj, newProto)方法。它返回一个布尔值,表示是否设置成功。
注意:
如果无法设置目标对象的原型(比如,目标对象禁止扩展),Reflect.setPrototypeOf方法返回false。
Iterator
介绍
Iterator(迭代器)是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable),可以使用for...of 。
部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口
任意一个对象的 Symbol.iterator 方法,等于该对象的遍历器生成函数
对象(Object)之所以没有默认部署Iterator接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
对象部署遍历器接口并不是很必要,因为这时对象实际上被当作 Map 结构使用,Map 结构可以使用for...of,ES5 没有 Map 结构,而 ES6 原生提供了。
作用
一是为各种数据结构,提供一个统一的、简便的访问接口;
二是使得数据结构的成员能够按某种次序排列;
三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费
原生具备 Iterator 接口的数据结构如下:
Array,Map,Set,String,TypedArray,函数的 arguments 对象,DOM NodeList对象
遍历器对象的方法:
next() 执行下一次
return() return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法
throw() 抛出错误
实例
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) { //只能next()
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
function makeIterator(array) {//既能next(),又能for...of。 与generator函数很像,但多了yield表达式 可以多次next()
var nextIndex = 0;
return {
[Symbol.iterator]:function(){return this},
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
//上面代码定义了一个makeIterator函数,它是一个遍历器生成函数,作用就是返回一个遍历器对象(it)
Generator
介绍
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
执行 Generator 函数会返回一个遍历器对象( {next:function(){...}部分 ),也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数( function(){return {next:function(){...}}} )。
返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
***Generator函数是遍历器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性。
特征
Generator 函数是一个普通函数,但是有 两个特征。
(1)function关键字与函数名之间有一个星号;
(2)函数体内部使用yield表达式
遍历器对象的next方法的运行逻辑如下
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
注意:
yield表达式如果用在另一个表达式之中,必须放在圆括号里面 //console.log('Hello' + (yield 123));
Generator 函数返回的遍历器对象方法
var g = function* () {}
g.next(实参) yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值
实例:
var y = yield x ;var z = yield (y / 3);y = 实参 ,上一个yield表达式的返回值
注意:
由于next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数是无效的。
g.throw() 可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
实例:
var g = function* () {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
// 内部捕获 a
// 外部捕获 b
//由于 Generator 函数内部的catch语句已经执行过了,不会再捕捉到这个错误了,所以这个错误就被抛出了 Generator 函数体,被函数体外的catch语句捕获
//如果 Generator 函数内部没有部署try...catch代码块,那么throw方法抛出的错误,将被外部try...catch代码块捕获
//如果 Generator 函数内部和外部,都没有部署try...catch代码块,那么程序将报错,直接中断执行
//throw方法抛出的错误要被内部捕获,前提是必须至少执行过一次next方法
throw方法被捕获以后,会附带执行下一条yield表达式。也就是说,会附带执行一次next方法。只要 Generator 函数内部部署了try...catch代码块,那么遍历器的 throw方法抛出的错误,不影响下一次遍历
throw方法可以接受一个参数,该参数会被catch语句接收,建议抛出Error对象的实例。
g.return()//Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。
实例:
g.return('foo') // { value: "foo", done: true }
g.return() // { value: undefined, done: true }
function* numbers () {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var g = numbers();
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.return(7) // { value: 4, done: false }
g.next() // { value: 5, done: false }
g.next() // { value: 7, done: true }
如果 Generator 函数内部有try...finally代码块,且正在执行try代码块,那么return方法会导致立刻进入finally代码块,执行完以后,整个函数才会结束。
next()、throw()、return()的作用
next()、throw()、return()它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式 实例: const g = function* (x, y) { let result = yield x + y; return result; };
const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}
(1)、gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;
(2)、gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));
(3)、gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
yield* 表达式:
用来在一个 Generator 函数里面执行另一个 Generator 函数
从语法角度看,如果yield表达式后面跟的是一个遍历器对象,需要在yield表达式后面加上星号,表明它返回的是一个遍历器对象。这被称为yield*表达式
yield* fn //fn表示要执行的Generator函数
如果yield*后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员
如果被代理的 Generator 函数有return语句,那么就可以向代理它的 Generator 函数返回数据 //var v = yield* foo();
因为Generator 函数返回的总是遍历器对象,而不是this对象。//注意Generator 函数内部的this