ES6笔记(纯干货)
一、Symbol
新的数据类型,表示独一无二的值
通过symbol函数生成
let s=Symbol();
对象属性名的两种表示方法:1、原有字符串表示。2、Symbol表示
Symbol可接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台输出,或者是转为字符串时比较容易区分
如果Symbol的参数是一个对象,则会调用toString方法将其转换成为字符串,然后生成一个Symbol值
Symbol值不能与其他类型的值进行运算,否则会报错
Symbol值可以显式的转为字符串
let sym=Symbol('My Symbol');
String(sym); //'Symbol(My Symbol)'
sym.toString(); //'Symbol(My Symbol)'
Symbol值也可以转换成为布尔值,但是不能转换为数值
let sym=Symbol();
Boolean(sym); //true
!sym; //false
Number(sym); //TypeError
Symbol值作为对象的属性名时不能使用点运算符,只能用方括号
在对象内部使用Symbol值定义属性时,也只能用方括号
let sym=Symbol();
let a={};
a.sym='Hello';
a[sym]; //undefined
s['sym']; //'Hello'
Symbol类型的值还可以定义一组常量,保证这些常量都是不相等的
(一)属性名遍历
Object.getOwnPropertySymbols():返回一个数组,成员是当前对象的所有作用属性名的Symbol值
Reflect.ownKeys():以数组的形式返回所有键名,包括常规键名和S也Symbol键名
以Symbol值作为属性名的属性不会被常规方法遍历得到(可为对象定义一些非私有但又希望只用于内部的方法)
Symbol.for():可重新使用同一个Symbol值
参数:一个字符串
作用:搜索有没有以该参数作为名称的Symbol值,若有则返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值
Symbol.for()与Symbol都可以生成新的Symbol
区别:前者会被登记在全局环境*搜索,后者不会
Singleton模式:调用一个类,并且在任何时候都返回同一个实例
(二)内置的Symbol值
对象的Symbol.hasInstance属性指向一个内部方法,对象使用instanceof运算符是会调用这个方法,判断该对象是否为某个构造函数的实例
class Myclass{
[Symbol.hanInstance](foo){
return foo instanceof Array;
}
}
[1,2,3] instanceof new Myclass; //true
对象的Symbo.isConcatSpreadable属性等于一个布尔值,表示该对象在使用Array.prototype.concat()时是否可以展开
let arr1=['c','d'];
['a','b'].concat(arr1,'e'); //['a','b','c','d','e']
arr1[Symvol.isConcatSpreadable] //undefined
let arr2=['c','d'];
arr2[Symbol.isConcatSpreadable]=false;
['a','b'].concat(arr2,'e'); //['a','b',['c','d'],'e']
数组的默认行为是可以展开的,Symbol.isConcatSpreadable属性等于undefined或者true,都可以
类似于数组的对象也可以展开,但它的Symbol.isConcatSpreadable属性默认为false,必须手动打开、
let obj={length:2,0:'c',1:'d'};
['a','b'].concat(obj,'e'); //['a','b',obj,'e']
obj[Symbol,isConcatSpreadable]=true;
['a','b'].concat(obj,'e'); //['a','b','c','d','e']
对于一个类而言,Symbol.isConcatSpreadable属性必须写成实例的属性
Symbol.species
对象的Symbol.species属性指向当前对象的构造函数,使用这个函数返回的函数来创造新的实例对象
定义Symbol.species属性要用get读取数据
class Array extends Array{
//覆盖父类Array的构造函数
static get [Symbol.species](){return Array;}
}
Symbol.match
对象的Symbol.match属性指向一个函数,当执行str.match(obj)时,如果该属性存在,则会调用它的返回值
Symbol.replace
对象的Symbol.replace属性指向一个方法,当对象被String.prototype.replace方法调用时会返回改方法的返回值
Symbol.split
对象的Symbol.split属性指向一个方法,当对象被String.prototype.split方法调用时会返回改方法的返回值
Symbol.iterator对象的Symbol.iterator属性指向该对象默认的遍历方法
Symbol.toPrimitive
对象的Symbol.toPrimitive属性指向一个方法,对象在转化为原始数据类型时会调用这个方法,返回该对象的原始数据类型
参数:字符串,表示当前运算模式
- Number:需要转化为数值
- String:需要转化为字符串
- Default:可转化为数组,也可转化为字符串
Symbol.toStringTag
对象的Symbol.toStringTag属性指向一个方法,在对象上调用Object.prototype.toString()时,如果这个属性存在,其返回值会出现在toString方法返回值的字符串中,表示对象的类型
Symbol.unscopables
对象的Symbol.unscopables属性指向一个对象,指定了使用with关键字时,那些属性会被with环境排除
二、Set和Map
(一)Set
类似于数组,其成员唯一,不重复
Set本身是一个构造函数,用于生产Set数据结构
let s=new Set();
Set函数可以接受一个数组,作为参数,用于初始化
向Set加入值时不会发生数据转换,即1和’1’为不同的值
在Set内部,两个NaN相等
(1)Set实例的属性
- Set.prototype.Constructor():构造函数,就是Set()
- Set.prototype.size():返回Set实例成员总数
- add(value):添加值,返回Set本身
- delete(value):删除值,返回一个布尔值,表删除是否成功
- has(value):返回布尔值,表参数是否为Set成员
- clear():清除所有成员,无返回值
(2)遍历
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach(function(){}):使用回调函数遍历每个成员,无返回值(可加参2,表示绑定的this对象)
Set的遍历顺序就是插入顺序
若想同步的改变原来的Set结构,可利用原Set映射出一个新的结构再复制给原Set结构,或者使用Array.from()
(二)WeaKSet
与Set类似,表不重复的集合
与Set的区别
WeakSet的成员只能是对象,不能是其他值
WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用
WeakSet的成员不能引用,因为其随时可能消失
WeakSet本生是一个构造函数,使用生成WeakSet数据结构
let w = new WeakSet();
可接受一个数组或者类似于数组的对象作为参数来初始化
WeakSet的方法
- WeakSet.prototype.add(value ):添加新成员
- WeakSet.prototype.delete(value):删除指定成员
- WeakSet.prototype.has(value):返回布尔值,表指定值是否在WeakSet实例中
WeakSet无size属性,无法遍历其成员
(三)Map
类似于对象,也是键值组合
其键的范围不限于字符串,可为各种数据类型的值(包括对象)均可当做键
使用Map()构造函数生成
let m = new Map();
Map可接受一个数组作为参数,其数组成员为一个个表示键值对的数组
若一个键多次赋值,则后面的覆盖前面的值
若读取一个未知的键,则返回undefined
Map的键实际上绑定的是地址值,只要地址不同,即视为两个键(解决了同名属性碰撞的问题)
(1)Map实例的属性方法
size
返回Map结构的成员总数
set(key,value)
设置key值所对应的键,然后返回Map结构
若key已经有值,则赋值更新,否则新生成该键值
get(key)
获取key对应的值,若找不到key则返回undefined
has(key)
返回一个布尔值,表示ley是否在Map结构中
delete(key)
删除某个键,删除成功则返回true,反之返回false
clear()
清除所有成员,无返回值
(2)遍历
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach(function(){}):遍历Map所有成员
Map的遍历顺序就是插入顺序
(四)Map与其他数据类型的转化
(1)Map转数组
Map转化为数组最快的方法时结合使用扩展运算符( . . . )
(2)数组转Map
将数组传入构造函数即可
(3)Map转对象
若Map所有键都是字符串,则可以转为对象
function strMapToObj(strMap){
let obj = Object.create(null);
for (let [k,v] of strMap){
obj[k]=v;
}
return obj;
}
(4)对象转Map
function objToStrMap(obj){
let strMap=new Map();
for(let k of Object.keys(obj)){
strMap.set(k.obj[k]);
}
return strMap;
}
(5)Map转JSON
情况一:Map键名都是字符串,可以转为对象JSON
function StrMapToJson(StrMap){
reutrn JSON.stringify(strMapToObj(strMap));
}
情况二:Map键名中含有非字符串,转为数组JSON
function mapToArrayJson(map){
return JSON.stringify(...map);
}
(6)JSON转Map
正常情况所有键名都是字符串
function jsonToStrMap(jsonStr){
return objToStrMap(JSON.parse(jsonStr));
}
特殊情况:在整个JSON就是一个数组,且数组成员本身又是由一两个成员的数组,此时应该一一对应的转为Map(数组转为JSON的逆操作)
function jsonToMap(jsonStr){
return new Map(JSON.parse(jsonStr));
}
(五)WeakMap
与Map结构类似,也用于生成键值对的集合
通过WeakMap函数生成
let wMap = new weakMap();
可使用set方法添加成员
可接受一个数组,作为构造函数的参数
WeakMap与Map的区别
-
WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名(即数组和Symbol值作为WeakMap的键名时会报错)
-
WeakMap的键名所指向的对象不计入垃圾回收机制(会自动被移除,有助于防止内存泄漏)
-
WeakMap没有遍历操作,也,没有size属性
-
无法清空,即没有clear()方法
WeakMap的语法
- get()
- set()
- has()
- delete()
三、proxy
用于某些操作的默认行为,等同于在语言层面做出修改
可理解为在目标对象前设置的一个“拦截”层,外界访问目标对象时,先通过拦截层,可对外界的访问进行过滤和改写
使用Proxy构造函数,生成proxy实例
let p = new Proxy(target,handler);
- target:目标对象
- handler:用来定制拦截行为的对象(若不设置任何拦截,等同于直接通向原对象)
可将proxy对象设置到object.proxy属性,可在object对象上直接调用
Proxy实例也可作为其他对象的原型对象
Proxy的所有拦截操作
get(target,propKey,receiver)
拦截对象某个属性的读取,最后一个参数为可选对象
若访问目标对象不存在的属性,会抛出一个错误
若没有这个拦截函数,访问不存在的属性只会返回undefined
get方法可以继承
可以利用proxy将get转变为执行某个函数,实现属性的链式操作
set(target,propKey,value,receiver)
拦截对象的设置,返回一个布尔值
利用set方法可以实现数据绑定(即每当对象发生变化,自动跟新DOM)
若目标对象的某个属性不可配置也不可写,只能返回同样的值,否则报错
has(target,propKey)
拦截propKey in proxy的操作,返回一个布尔值(拦截in运算符)
若对象不可配置或禁止扩展,则报错
不判断一个属性是对象自身的还是继承的属性
拦截对for…,in 永不生效
deleteProperty(target,propKey)
拦截delete proxy[proKey]操作,返回一个布尔值
若这个方法抛出错误或者返回false,则当前属性无法被delete删除
目标对昂自身不可配置的属性不能被deleteProperty方法删除,否则报错
ownKeys(target)
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个由目标对象所有自身属性的属性名组成的数组
返回的数组成员只能是字符串或者Symbol值,
若有其他类型的值,或返回的根本不是数组,则报错
若目标对象自身含有不可配置的属性,则改属性必须被ownKeys返回,否则报错
若目标对象不可扩展,则返回的数组中必须包原对象的所有属性,且不能含有其他属性,否则报错
注:使用Object.keys()方法时有三类属性会被ownKeys方法自动过滤
- 目标对象上不存在的属性
- 属性名为Symbol值
- 不可遍历的属性
getOwnPropertyDescriptor(target,propKey)
拦截Object.getOwnPropertyDescriptor(proxy,propKey),返回属性的描述对象或undefined
defineProperty(target,propKey,PropDesc)
拦截Object.defineProperty(proxy,propKey,propDesc)、Object.defineProperties(proxy、propDescs),返回一个布尔值
若目标对象不可扩展,则defineProperty不能增加目标对象中不存在的属性,否则报错
若目标对象中某个属性不可写或不可配置,则defineProperty不得改变这两个设置
preventExtensions(proxy)
拦截Object.preventpreventExtensions(proxy),返回一个布尔值,否则会被自动转为布尔值
限制:只有目标对象不可扩展时,proxy.prevrntExtensions才能返回true,否则报错
解决方案:可在proxy.prevrntExtensions()方法中调用一次Object.preventpreventExtensions()
let p = new proxy({},{
preventExtensions:function(target){
Object.preventpreventExtensions(target);
return true;
}
})
getPrototypeOf(target)
拦截Object.getPrototype(proxy),返回一个对象或者null,否则报错
若目标对象时一个函数,name还有两种额外操作可以拦截
若目标对象不可扩展,则返回目标对象的原型对象
主要用于拦截对象原型
- Object.prototype._ _ proto _ _
- Object.prototype.isPrototypeOf()
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- instanceof
setPrototypeOf(target)
拦截Object.setPrototypeOf(),返回一个布尔值,否会被自动转为布尔值
若目标对象不可扩展,setPrototypeOf()不得改变目标对象的原型
isExtensible(target)
拦截Object.isExtensible(proxy),返回一个布尔值
强限制:返回值必须与目标对象的isExtensible属性保持一致,否则报错
apply(target,object,args)
拦截proxy实例,并将其作为函数调用的操作
拦截函数的调用、call、apply操作
直接调用Reflect.apply()也会被拦截
可接受三个参数:
- 目标对象
- 目标对象的上下文对象(this)
- 目标对象的参数数组
construct(target,args)
拦截Proxy实例作为构造函数调用的操作,比如new proxy(…args)
拦截new命令
let handler = {
construct (target,args,newTatget){
return new target(...args);
}
};
可接受两个参数
- target:目标对象
- args:构造函数的参数对象
返回一个对象,否则报错
Proxy.revocable(target,handler)
返回一个可取消的proxy实例
四、Reflect
(一)设计目的
- 将Object对象上一些明显属于语言的方法放在Reflect上。(从Reflect对象上可以获取语言内部的方法)
- 修改一些Object方法的返回结果,让其变得合理
- 让Object操作都编程函数行为
- proxy对象的方法在Reflect上可以找到与之对应的方法
(二)静态方法
Reflect.get(target,name,receiver)
查找并返target对象的那么属性,若没有则返回undefined
若那么属性部署了读取函数,则读取函数的this绑定receiver
若第一个参数不是对象,则报错
Reflect.set(target,name,value,receiver)
设置target的name属性等于value
若name属性设置了赋值函数,则赋值函数的this绑定receiver
若第一个参数不是对象,则报错
Reflect.set会触发Proxy.defineProperty拦截
Reflect.has(obj,name)
对应name in obj中的in运算符
若一个参数不是对象,则Reflect和in都会报错
Reflect.deletePrototypety(obj,name)
删除对象的属性,等同于delete obj[name]
返回一个布尔值,若删除成功,或删除的属性不存在,则返回true,否则返回false
Reflect.construct(target,args)
等同于new target(…args)
Reflect.getPrototyprOf(obj)
读取对象的 _ _ proto _ _属性,等同于Object.getPrototype(obj)
两者的区别:若参数不是对象,后者会将其转化为对象再进行,而前者则报错
Reflect.setPrototypeOf(obj,newProto)
设置对象的 _ _ proto _ _属性,返回第一个参数
等同于Object.setPrototype(obj,newProto)
若第一个参数不是对象,后者返回第一个对象本身,前者报错
若第一个参数是null或者undefined,两者均报错
Reflect.apply(func,thisArgs,args)
绑定this对象后执行给定函数
等同于Function.prototype.apply.call(func,thisArgs,args)
Reflect.definePropertyOf(target,propertyKey,attribute)
为对象定义属性
等同于Object.definePropertyOf()
Reflect.getOwnPropertyDescriptor(target,propertyKey)
获得指定属性的描述对象
等同于Object.getOwnPropertyDescriptor()
两者区别:若第一个参数不是对象,则后者不会报错,并返回undefined,而前者抛出错误,表示参数非法
Reflect.isExtensible(target)
返回布尔值,表示当前函数是否可扩展
等同于Object.isExtensible()
若第一个参数不是对象,后者返回false(因为非对象不可扩展),前者报错
Reflect.preventExtensions(target)
使一个对象变为不可扩展的,返回布尔值,表示操作是否成功
等同于Object.preventExtensions()
Reflect.OwnKeys(target)
返回对象的所有属性
五、promise
异步编程解决方案
特点:
- 对象状态不受外界影响
- 一旦状态改变之后就不会在变,随时可以获取到这个结果
promise对象代表一个异步操作,三种状态:
- Pending:进行中
- Fulfilled:已成功
- Rejected:已失败
只有异步操作的结果可以决定当前的状态,其他操作均不行
使用Promise构造函数生成promise实例
let p = new Promise(function(target,reject){});
promise新建后立即执行
promise接受一个函数作参数,函数的两个参数有JS引擎提供,不用自己部署
target:异步操作成功时调用,将结果作为参数传出去
reject:异步操作失败时调用,将报出的错作为参数传出去
(一)then
为promise实例添加状态改变时的回调函数,返回一个新的promise对象实例
then是定义在原型对象Promise。prototype上的
可用then分别指定Resolved状态和Rejectd状态的回调函数
then的参数为两个回调函数,都接受promise对象传出的值为参数
- 参1:promise对象状态变为Resolved时调用
- 参2:promise对象状态变为Rejectd时调用(可选)
(二)catch
指定发生错误时的回调函数
返回一个新的promise对象(后面可接着调then)
可获取then指定的回调函数在运行中抛出的错误
promise的错误会一直向后传递,直到被捕获为止
若前面的then没有报错,则会跳过catch
(三)Promise.all()
将多个promise实例包装成一个新的promise实例
(四)promise.race()
将多个promise实例包装成一个新的promise实例
(五)promise.resolve()
将现有的对象转为Promise
若参数是promise实例:则直接返回这个实例
若参数是thenable对象:则先转成promise对象,在执行thenable对象的then方法
thenable对象:具有then方法的对象
若参数不是thenable对象或者不是对象:promise.resolve返回一个新的Promise对象,状态为Resolved
若不带音任何参数:则返回一个状态为Resolved状态的对象
(六)promise.reject()
返回一个状态为Rejected的新的promise对象
(七)附加方法
done()
处于回调链尾端,保证抛出任何可能出现的错误
可像catch那样使用
有参无参均可,done可捕获到任何可能出现的错误,并向全局抛出
finally()
指定不管promise对象最后状态如何都会执行的操作
与done()的区别:参数为普通的回调函数,不管怎样都必须执行