es5严格模式
-
理解:除了正常运行模式(混杂模式),es5添加了第二种运行模式:”严格模式“
这种模式使得js在更严格的语法条件下运行
-
目的/作用
-
消除js语法的一些不合理,不严谨之处,减少一些怪异行为
-
消除代码运行的一些不安全之处,为代码的安全运行保驾护航。
-
为未来新版本的js做好铺垫
-
-
使用
-
在全局或函数的第一条语句定义为:‘use strict’;
-
如果浏览器不支持,只解析为一条简单的语句,没有任何副作用
-
-
语法和行为改变
-
必须用var声明变量
-
禁止自定义的函数中的this指向window
-
创建eval作用域
-
对象不能有重名的属性
-
json对象扩展
-
JSON.stringify(obj/arr)- js对象(数组)转换为json对象(数组)
-
JSON.parse(json)- json对象(数组)转换为js对象(数组)
Object对象方法扩展
- es5给Object扩展了一些静态方法,常用的有两个
-
Object.create(prototype,[descriptors])-
作用:以指定对象为原型创建新的对象
-
为新的对象制定新的属性,并对属性进行描述
-
value:指定值 -
configurable:标识当前属性是否可以被删除,默认为false -
writable:标识当前属性值是否是可修改的,默认为false -
enumerable:标识当前属性是否能用for in枚举 默认为false
-
-
Object.defineProperties(object,descriptors)-
作用:为指定对象定义扩展多个属性
-
get:用来获取当前属性值的回调函数获取扩展属性值的时候自动调用
-
set:修改(监听)当前属性值的触发的回调函数,并且实参即为修改后的值 -
存取器属性:
setter,getter一个用来存值,一个用来取值
-
对象本身的两个方法
-
get propertyName(){ }用来得到当前属性值的回调函数 -
set propertyName(){ }用来监视当前属性值变化的回调函数
数组的扩展
-
Array.prototype.indexOf(value): 得到值在数组中的第一个下标 -
Array.prototype.lastIndexOf(value): 得到值在数组中的最后一个下标 -
Array.prototype.forEach(function(item, index){}): 遍历数组 -
Array.prototype.map(function(item, index){}): 遍历数组返回一个新的数组,返回加工之后的值 -
Array.prototype.filter(function(item, index){}): 遍历过滤出一个新的子数组, 返回条件为true的值
字符串的扩展
-
String.fromCodePoint方法,可以识别0xFFFF的字符 -
ES6为字符串添加了遍历器接口,使得字符串可以被
for...of循环遍历。这个遍历器最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。 -
字符串实例的
at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。 -
ES6提供字符串实例的
normalize()方法,用来将字符的不同表示方法统一为同样的形式,这称为Unicode正规化。 -
includes():返回布尔值,表示是否找到了参数字符串。startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。 -
repeat方法返回一个新字符串,表示将原字符串重复n次 -
如果某个字符串不够指定长度,会在头部或尾部补全。
padStart()用于头部补全,padEnd()用于尾部补全 -
String.raw方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串String.rawHi\n${2+3}!; // "Hi\\n5!" String.rawHi\u000A!; // 'Hi\\u000A!'
正则表达式的扩展
-
ES6中,如果
RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。 -
字符串对象共有4个方法,可以使用正则表达式:
match()、replace()、search()和split()。ES6将这4个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上。 -
ES6对正则表达式添加了u修饰符,含义为“
Unicode模式”,用来正确处理大于\uFFFF的Unicode字符。 -
点(.)字符在正则表达式中,含义是除了换行符以外的任意单个字符。对于码点大于
0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。 -
ES6新增了使用大括号表示
Unicode字符,这种表示法在正则表达式中必须加上u修饰符,才能识别。 -
ES6为正则表达式新增了
flags属性,会返回正则表达式的修饰符。
数值的扩展
-
ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。
-
如果要将0b和0o前缀的字符串数值转为十进制,要使用
Number方法。 -
Number.isFinite()用来检查一个数值是否为有限的 -
Number.isNaN()用来检查一个值是否为NaN -
ES6将全局方法
parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
6.Number.isInteger()用来判断一个值是否为整数。
7.ES6在Number对象上面,新增一个极小的常量Number.EPSILON
Math对象的扩展
-
Math.trunc方法用于去除一个数的小数部分,返回整数部分 -
Math.sign方法用来判断一个数到底是正数、负数、还是零 -
Math.cbrt方法用于计算一个数的立方根。 -
JavaScript的整数使用32位二进制形式表示,Math.clz32方法返回一个数的32位无符号整数形式有多少个前导0 -
Math.imul方法返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数 -
Math.fround方法返回一个数的单精度浮点数形式 -
Math.hypot方法返回所有参数的平方和的平方根 -
Math.expm1(x)返回ex - 1,即Math.exp(x) - 1 -
Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x) -
Math.log10(x)返回以10为底的x的对数。如果x小于0,则返回NaN。 -
Math.log2(x)返回以2为底的x的对数。如果x小于0,则返回NaN。 -
ES2016新增了一个指数运算符(**)。
数组的扩展
-
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。类似数组的对象,本质特征只有一点,即必须有length属性,Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。 -
Array.of方法用于将一组值,转换为数组。 -
数组实例的
copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。它接受三个参数。- target(必需):从该位置开始替换数据。
- start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
-
数组实例的
find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined -
数组实例的
findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。 -
fill方法使用给定值,填充一个数组。 -
ES6提供三个新的方法——
entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。 -
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。该方法属于ES7,但Babel转码器已经支持。 -
Map结构的has方法,是用来查找键名的Set结构的has方法,是用来查找值的 -
数组的空位指,数组的某一个位置没有任何值。空位不是
undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值
数组(Array)和对象(Object),ES6又添加了Map和Set。这样就有了四种数据集合
函数的扩展
-
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
-
如果参数默认值是变量,那么参数就不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
-
有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入
undefined。 -
函数的
length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真,如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。 -
ES6 引入
rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 -
扩展运算符(
spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列,如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错 -
函数的
name属性,返回该函数的函数名。Function构造函数返回的函数实例,name属性的值为anonymous。bind返回的函数,name属性值会加上bound前缀 -
函数绑定运算符是并排的两个双冒号(
::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。 -
尾调用就是指某个函数的最后一步是调用另一个函数。尾调用优化”,即只保留内层函数的调用帧。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用帧只有一项,这将大大节省内存。这就是“尾调用优化”的意义。
注意,只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”。
-
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
-
柯里化,意思是将多参数的函数转换成单参数的形式。这里也可以使用柯里化。
对象的扩展
-
属性,对象简写时如果某个方法的值是一个
Generator函数,前面需要加上星号。var obj = { * m(){ yield 'hello world'; } }; -
属性名表达式与简洁表示法,不能同时使用,会报错
-
函数的
name属性,返回函数名。对象方法也是函数,因此也有name属性。如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。 -
有两种特殊情况:
bind方法创造的函数,name属性返回bound加上原函数的名字;Function构造函数创造的函数,name属性返回anonymous。 -
如果对象的方法是一个
Symbol值,那么name属性返回的是这个Symbol值的描述。 -
ES5比较两个值是否相等,只有两个运算符:相等运算符(
==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。不同之处只有两个:一是+0不等于-0,二是NaN等于自身。 -
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target) -
Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性 -
对象的每个属性都有一个描述对象(
Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。 -
Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。 -
Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象
属性的遍历
-
for...infor...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或字符串,也不管是否可枚举。
ES6中零散的知识点
-
Function.prototype.bind(obj):- 作用: 将函数内的this绑定为obj, 并将函数返回
-
面试题: 区别
bind()与call()和apply()?-
都能指定函数中的
this -
call()/apply()是立即调用函数 -
bind()是将函数返回,不会立即调用函数 -
call()直接从第二个参数开始,依次传入
-
apply()第二参数必须是数组,传入放在数组里 -
bind传参的方式同call一样
-
-
暂时性死区:在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
let与const关键字
- let关键字
-
作用:
- 与
var类似,用于声明一个变量
- 与
-
特点:
-
在块级作用域有效
-
不允许在相同作用域内,重复声明同一个变量
-
不会预处理,不存在变量提升
-
-
应用:
-
循环遍历加监听
-
使用
let取代var是趋势
-
-
const关键字-
作用:定义一个常量
-
特点:
-
不能修改
-
立即初始化
-
其他特点同
let
-
-
应用:
- 保存不用改变的数据
-
本质:
- const实际上并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
-
块级作用域
-
外层代码块不受内层代码块的影响
-
允许块级作用域的任意嵌套
-
外层作用域无法读取内层作用域的变量
-
内层作用域可以定义外层作用域的同名变量
-
es5中,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域中声明,但是es6引入了块级作用域,明确允许在块级作用域之中声明函数,但是尽量避免在块级作用域内声明函数。如果确实需要,应该写成函数表达式,而不是函数声明语句,因为函数声明会提升,类似于
var。 -
es6的块级作用域声明函数时必须使用大括号
-
块级作用域没有返回值,是一个语句,要想有返回值的话用do表达式,
let 变量名 = do{
}
es6声明变量的六种方法
-
var
-
function
-
let
-
const
-
import
-
class
顶层对象的概念
-
在浏览器中顶层对象是window
-
在Node中,顶层对象是global
变量的解构赋值
-
理解:
- 从对象或数组中提取数据,并赋值给变量(多个)
-
本质:
- 这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
-
对象的解构赋值
let{n,a}=[n:'tom',a:12];let { foo: baz } = { foo: "aaa", bar: "bbb" }; baz // "aaa" foo // error: foo is not defined- 上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo -
数组的解构赋值
let[a,b]=[1,'at']; -
用途
- 给多个形参赋值
-
对象的解构可以指定默认值,默认值生效的条件是,对象的属性值严格等于
undefined -
解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错
// 报错
let {foo: {bar}} = {baz: 'baz'}; -
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于
undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。 -
解构赋值的用途:
-
交换变量的值
-
从函数返回多个值
-
函数参数的定义
-
提取JSON数据
-
设置函数参数的默认值
-
遍历Map结构
-
模板字符串:简化字符串的拼接
-
模板字符串必须使用``包含
-
变化的部分使用
${xxx}定义 -
模板字符串之中还能调用函数
-
模板字符串能嵌套
简化的对象写法
-
省略同名的属性值
-
省略方法的function
-
例如:
let x =1;
let y=2;
let point = {
x,
y,
setX(x){this.x=x}
};
箭头函数
-
作用:定义匿名函数
-
基本语法:
-
没有参数:
()=>console.log('xxx') -
一个参数:
i=>i+2 -
大于一个参数:
(i,j)=>i+j -
函数体不用大括号:默认返回结果
-
函数体如果有多个语句,需要用{}包围,若有需要返回的内容,需要手动返回
-
-
适用场景:多用来定义回调函数
-
箭头函数的特点:
-
简洁
-
箭头函数没有自己的
this,箭头函数的this不是调用的时候决定的,而是再定义的时候处在的对象就是它的this -
扩展理解:箭头函数的
this看外层的是否有函数。如果有,外层函数的
this就是内部箭头函数的this如果没有,则
this是window
-
-
箭头函数有几个使用注意点。
-
函数体内的
this对象,就是定义时所在的对象,而不是使用时所在的对象。 -
不可以当作构造函数,也就是说,不可以使用
new命令,否则会抛出一个错误。 -
不可以使用
arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。 -
不可以使用
yield命令,因此箭头函数不能用作Generator函数。 -
除了
this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target
三点运算符
-
- 用途
-
rest(可变)参数- 用来取代
arguments但比arguments灵活,只能是最后部分形参参数
- 用来取代
function fun(...values) {
console.log(arguments);
arguments.forEach(function (item, index) {
console.log(item, index);
});
console.log(values);
values.forEach(function (item, index) {
console.log(item, index);
})
}
fun(1,2,3);
-
扩展运算符
let arr1 = [1,3,5];let arr2 = [2,...arr1,6];arr2.push(...arr1);
- 形参的默认值----当不传入参数的时候默认使用形参里的默认值
function Point(x = 1,y = 2) {
this.x = x;
this.y = y;
}
promise对象原理
-
特点
-
Promise对象有以下两个特点。-
对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 -
一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的
-
-
-
ES6的
Promise是一个构造函数, 用来生成promise实例-
Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。 -
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数 -
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例 -
Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例 -
有时需要将现有对象转为
Promise对象,Promise.resolve方法就起到这个作用
-
参数是一个
Promise实例如果参数是
Promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。 -
参数是一个
thenable对象thenable对象指的是具有then方法的对象,Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。 -
参数不是具有
then方法的对象,或根本就不是对象如果参数是一个原始值,或者是一个不具有
then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved.
-
-
done()Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误
-
finally()-
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
-
不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个Resolved状态的Promise对象Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected
-
-
优点和缺点
- 有了
Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise也有一些缺点。-
首先,无法取消
Promise,一旦新建它就会立即执行,无法中途取消。 -
其次,如果不设置回调函数,
Promise内部抛出的错误,不会反应到外部。 -
第三,当处于
Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
- 有了
-
使用
promise基本步骤(2步):-
创建promise对象
-
let promise = new Promise((resolve, reject) => {
//初始化promise状态为 pending
//执行异步操作
if(异步操作成功) {
resolve(value);//修改promise的状态为fullfilled
} else {
reject(errMsg);//修改promise的状态为rejected
}
})
* 调用promise的then()
promise.then(function(
result => console.log(result),
errorMsg => alert(errorMsg)
))
-
promise对象的3个状态-
pending: 初始化状态 -
fullfilled: 成功状态 -
rejected: 失败状态
-
-
应用:
- 使用
promise实现超时处理
- 使用
-
使用promise封装处理ajax请求
let request = new XMLHttpRequest();
request.onreadystatechange = function () {
}
request.responseType = 'json';
request.open("GET", url);
request.send();
Symbol
-
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
-
概念:ES6中的添加了一种原始数据类型
symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象) -
Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。 -
特点:
-
Symbol属性对应的值是唯一的,解决命名冲突问题 -
Symbol值不能与其他数据进行计算,包括同字符串拼串 -
for in,for of遍历时不会遍历symbol属性。
-
-
使用:
-
调用
Symbol函数得到symbol值let symbol = Symbol();let obj = {};obj[symbol] = 'hello'; -
传参标识
let symbol = Symbol('one');let symbol2 = Symbol('two');console.log(symbol);// Symbol('one')console.log(symbol2);// Symbol('two') -
内置
Symbol值- 除了定义自己使用的
Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- 除了定义自己使用的
-
-
Symbol.iterator-
对象的
Symbol.iterator属性,指向该对象的默认遍历器方法
-
有一个
Object.getOwnPropertySymbols方法,可以获取指定对象的所有Symbol属性名。 -
概念:
iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制 -
作用:
-
为各种数据结构,提供一个统一的、简便的访问接口;
-
使得数据结构的成员能够按某种次序排列
-
ES6创造了一种新的遍历命令
for...of循环,Iterator接口主要供for...of消费。
-
-
工作原理:
-
创建一个指针对象(遍历器对象),指向数据结构的起始位置。
-
第一次调用
next方法,指针自动指向数据结构的第一个成员 -
接下来不断调用
next方法,指针会一直往后移动,直到指向最后一个成员 -
每调用
next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
-
-
value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。 -
当遍历结束的时候返回的
value值是undefined,done值为false
-
-
原生具备
iterator接口的数据(可用for of遍历)-
Array -
arguments -
set容器 -
map容器 -
String
-
-
使用三点运算符和解构赋值,默认去调用
iterator接口
Generator函数
-
概念:
-
ES6提供的解决异步编程的方案之一
-
Generator函数是一个状态机,内部封装了不同状态的数据, -
用来生成遍历器对象
-
可暂停函数(惰性求值),
yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
-
-
特点:
-
function与函数名之间有一个星号 -
内部用
yield表达式来定义不同的状态例如:
function* generatorExample(){ let result = yield 'hello'; // 状态值为hello yield 'generator'; // 状态值为generator }-
generator函数返回的是指针对象,而不会执行函数内部逻辑 -
调用
next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果undefined, done: false/true} -
再次调用
next方法会从上一次停止时的yield处开始,直到最后 -
yield语句返回结果通常为undefined, 当调用next方法时传参内容会作为启动时yield语句的返回值。 -
yield语句只能用在Generator函数里面,用在其他地方都会报错 -
yield语句如果用在一个表达式之中,必须放在圆括号里面 -
yield句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值. -
for...of循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法 -
Generator函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在Generator函数体内捕获. -
Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数. -
如果在
Generator函数内部,调用另一个Generator函数,默认情况下是没有效果的。 -
所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。
-
所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。
-
代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。因为多个异步操作形成了强耦合,只要有一个操作需要修改,它的上层回调函数和下层回调函数,可能都要跟着修改。这种情况就称为"回调函数地狱"
-
"协程",意思是多个线程互相协作,完成异步任务。
-
Iterator(遍历器)的概念
-
遍历器(
Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作 -
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。 -
Iterator的遍历过程是这样的。-
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
-
第一次调用指针对象的
next方法,可以将指针指向数据结构的第一个成员。 -
第二次调用指针对象的
next方法,指针就指向数据结构的第二个成员。 -
不断调用指针对象的
next方法,直到它指向数据结构的结束位置。
- 每一次调用
next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
-
-
在ES6中,有三类数据结构原生具备
Iterator接口:数组、某些类似数组的对象、Set和Map结构 -
字符串是一个类似数组的对象,也原生具有
Iterator接口 -
return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句或continue语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法
async函数(源自ES2017)
-
概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
-
本质: Generator的语法糖
-
语法:
async function foo(){
await 异步操作;
await 异步操作;
}
-
特点:
-
不需要像
Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行 -
返回的总是
Promise对象,可以用then方法进行下一步操作 -
async取代Generator函数的星号*,await取代Generator的yield -
语意上更为明确,使用简单,经临床验证,暂时没有任何副作用
-
async函数内部return语句返回的值,会成为then方法回调函数的参数async函数有多种使用形式。 -
async函数返回的Promise对象,必须等到内部所有await命令后面的Promise对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。 -
只要一个
await语句后面的Promise变为reject,那么整个async函数都会中断执行。 -
for...of循环用于遍历同步的Iterator接口。新引入的for await...of循环,则是用于遍历异步的Iterator接口。
-
-
使用注意点
-
await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
-
多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
-
await命令只能用在async函数之中,如果用在普通函数,就会报错。
-
-
函数声明
async function foo() {} -
函数表达式
const foo = async function () {}; -
对象的方法
let obj = { async foo() {} }; obj.foo().then(...) -
Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);
- 箭头函数
const foo = async () => {};
异步Generator函数
-
就像
Generator函数返回一个同步遍历器对象一样,异步Generator函数的作用,是返回一个异步遍历器对象。 -
在语法上,异步
Generator函数就是async函数与Generator函数的结合。 -
通过
class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。 -
类的内部所有定义的方法,都是不可枚举的
-
一个类必须有
constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。 -
Class不存在变量提升 -
子类的原型的原型,是父类的原型。
-
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上
static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。 -
如果构造函数不是通过
new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的-
通过
class定义类/实现类的继承 -
在类中通过
constructor定义构造方法 -
通过
new来创建类的实例 -
通过
extends来实现类的继承 -
通过
super调用父类的构造方法 -
重写从父类中继承的一般方法
-
-
super这个关键字,既可以当作函数使用,也可以当作对象使用。-
第一种情况,
super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。 -
第二种情况,
super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
-
es6字符串的扩展
-
includes(str): 判断是否包含指定的字符串 -
startsWith(str): 判断是否以指定字符串开头 -
endsWith(str): 判断是否以指定字符串结尾 -
repeat(count): 重复指定次数
es6数值的扩展
-
二进制与八进制数值表示法: 二进制用0b, 八进制用0o
-
Number.isFinite(i): 判断是否是有限大的数 -
Number.isNaN(i): 判断是否是NaN -
Number.isInteger(i): 判断是否是整数 -
Number.parseInt(str): 将字符串转换为对应的数值 -
Math.trunc(i): 直接去除小数部分
es6数组的扩展
-
Array.from(v): 将伪数组对象或可遍历对象转换为真数组 -
Array.of(v1, v2, v3): 将一系列值转换成数组 -
find(function(value, index, arr){return true}): 找出第一个满足条件返回true的元素 -
findIndex(function(value, index, arr){return true}): 找出第一个满足条件返回true的元素下标
es6对象方法的扩展
-
Object.is(v1, v2)- 判断2个数据是否完全相等
-
Object.assign(target, source1, source2..)- 将源对象的属性复制到目标对象上
-
直接操作
__proto__属性let obj2 = {};obj2.__proto__ = obj1;
拷贝
-
数据类型:
-
数据分为基本的数据类型(
String, Number, boolean, Null, Undefined)和对象数据类型
-
基本数据类型:
特点: 存储的是该对象的实际数据
-
对象数据类型:
特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
-
-
复制数据
-
基本数据类型存放的就是实际的数据,可直接复制
let number2 = 2;let number1 = number2; -
克隆数据:对象/数组
-
-
区别: 浅拷贝/深度拷贝
-
判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
-
知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
let obj = {username: 'kobe'}let obj1 = obj;// obj1 复制了obj在栈内存的引用
-
-
常用的拷贝技术
-
arr.concat(): 数组浅拷贝 -
arr.slice(): 数组浅拷贝arr.assign():数组浅拷贝直接赋值给一个变量:浅拷贝
-
JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据 -
浅拷贝包含函数数据的对象/数组
-
深拷贝包含函数数据的对象/数组
-
-
浅拷贝(对象/数组):
- 特点“拷贝的引用,修改拷贝以后的数据会影响原数据,使得原数据不安全
-
深拷贝(深度克隆):
- 特点:拷贝的时候生成新数据,修改拷贝以后的数据不会影响原数据
-
思考:如何实现深拷贝
-
拷贝的数据里有对象/数组
-
拷贝的数据里不能有对象/数组,
-
即使有对象/数组可以继续遍历对象,数组拿到里边每一项值,一直到拿到是基本数据类型,然后再去复制,就是深拷贝
-
-
知识点储备
-
如何判断数据类型:
arr---->Arraynull ---->Null
-
typeof返回的数据类型:String,Number,Boolean,Undefined,Object,Function -
Object.prototype.toString.call(obj)
let result = ‘abcd’;result = null;result=[1,3];console.log(Object.prototype.toString.call(result).slice(8,-1)); -
-
for in 循环对象
let obj = {username:‘kobe’,age:39}; for(let i in obj){ console.log(i); } let arr=[1,3,'abc']; for(let i in arr){ console.log(i); } -
定义检测数据类型的功能函数
function checkedType(target ){ return Object.prototype.toString.call(target).slice(8,-1) } -
实现深度克隆--->对象/数组
function clone(target){ 判断拷贝的数据类型 let result,targetType = checkedType(target); if(targetType ==='Object'){ result={ }; }else if(targetType ==='Array'){ result=[ ]; }else{ return target; } } -
遍历目标数据
for(let i in target){
获取遍历数据结构的每一项值
let value = target[i];
if(checkedType(value)==='Object'|| checkedType(value)==='Array'){
对象/数组里嵌套了对象/数组,继续遍历获取到的value值
result[i]=clone(value)
}else{
result[i]=value;
}
}
return result;
}
set和get
-
Set容器 : 无序不可重复的多个value的集合体Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)-
Set() -
Set(array) -
add(value)添加某个值,返回Set结构本身 -
delete(value)删除某个值,返回一个布尔值,表示删除是否成功 -
has(value)返回一个布尔值,表示该值是否为Set的成员 -
clear()清除所有成员,没有返回值 -
size属性返回Set结构的成员总数
-
-
Map容器 : 无序的key不重复的多个key-value的集合体类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
-
Map() -
Map(array) -
set(key, value),set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键 -
get(key)get方法读取key对应的键值,如果找不到key,返回undefined -
delete(key)delete方法删除某个键,返回true。如果删除失败,返回false -
has(key)has方法返回一个布尔值,表示某个键是否在Map数据结构中 -
clear()clear方法清除所有成员,没有返回值 -
size属性返回Map结构的成员总数
-
-
for(let value of target){}循环遍历-
遍历数组
-
遍历
Set -
遍历
Map -
遍历字符串
-
遍历伪数组
-
-
指数运算符(幂):
** -
Array.prototype.includes(value): 判断数组中是否包含指定value
Proxy
-
Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改 -
Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。 -
get方法用于拦截某个属性的读取操作 -
set方法用来拦截某个属性的赋值操作 -
apply方法拦截函数的调用、call和apply操作。 -
apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。 -
has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。 -
construct方法用于拦截new命令 -
deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除 -
defineProperty方法拦截了Object.defineProperty操作 -
getOwnPropertyDescriptor方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined -
getPrototypeOf方法主要用来拦截获取对象原型。 -
isExtensible方法拦截Object.isExtensible操作 -
ownKeys方法用来拦截对象自身属性的读取操作。 -
preventExtensions方法拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。 -
setPrototypeOf方法主要用来拦截Object.setPrototypeOf方法。 -
Proxy.revocable方法返回一个可取消的Proxy实例。 -
Proxy代理的情况下,目标对象内部的this关键字会指向Proxy代理
reflect
-
Reflect.get(target, name, receiver) -
Reflect.get方法查找并返回target对象的name属性,如果没有该属性,则返回undefined -
Reflect.has方法对应name in obj里面的in运算符 -
Reflect.construct方法等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法 -
Reflect.getPrototypeOf方法用于读取对象的__proto__属性,对应Object.getPrototypeOf(obj)Reflect.getPrototypeOf和Object.getPrototypeOf的一个区别是,如果参数不是对象,Object.getPrototypeOf会将这个参数转为对象,然后再运行,而Reflect.getPrototypeOf会报错。 -
Reflect.apply方法等同于Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数。 -
一般来说,如果要绑定一个函数的
this对象,可以这样写fn.apply(obj, args),但是如果函数定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args) -
Reflect.defineProperty方法基本等同于Object.defineProperty,用来为对象定义属性 -
Reflect.getOwnPropertyDescriptor基本等同于Object.getOwnPropertyDescriptor -
Reflect.isExtensible方法对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展 -
Reflect.preventExtensions对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功 -
Reflect.ownKeys方法用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和 -
观察者模式(
Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行 -
修饰器(
Decorator)是一个函数,用来修改类的行为。 -
修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。
export 命令
-
模块功能主要由两个命令构成:
export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。其他 JS 文件就可以通过import命令加载这个模块 -
<script>标签打开defer或async属性,脚本就会异步加载。渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令。 -
defer与async的区别是:前者要等到整个页面正常渲染结束,才会执行;后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。 -
浏览器加载 ES6 模块,也使用
<script>标签,但是要加入type="module"属性。 -
采用
require命令加载 ES6 模块时,ES6 模块的所有输出接口,会成为输入对象的属性