欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6笔记(纯干货)

程序员文章站 2023-12-21 23:49:40
...

一、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

(一)设计目的

  1. 将Object对象上一些明显属于语言的方法放在Reflect上。(从Reflect对象上可以获取语言内部的方法)
  2. 修改一些Object方法的返回结果,让其变得合理
  3. 让Object操作都编程函数行为
  4. 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对象代表一个异步操作,三种状态:

  1. Pending:进行中
  2. Fulfilled:已成功
  3. 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()的区别:参数为普通的回调函数,不管怎样都必须执行

相关标签: ES6 前端 笔记

上一篇:

下一篇: