0


ES6--阮一峰版笔记

ES6

一. ES6变量声明方法

ES6共有六种变量声明方法:var、function、const、let、import、class
顶层对象属性:在浏览器中,顶层对象指window,在node中,顶层对象指global,用var、function命令声明的顶层的全局变量,依旧是顶层对象的属性(原ES5中,顶层对象的属性赋值与全局变量赋值为同一件事),用let 、const、class命令声明的全局变量,不属于顶层对象的属性
ES6新增globalThis顶层对象,在任何环境下都是存在的,globalThis指向全局环境下的this.

二. Symbol

  1. symbol:原始数据类型,表明独一无二的值。
  • Symbol值使用Symbol()函数生成,typeOf symbol值 输出为"symbol"。
  • Symbol()函数不能有用new 命令,因为Symbol是一个原始类型的值,不是对象。
  • Symbol值不能与其他类型值进行运算,会报错;但是Symbol值可以显示转为字符串,可以转为布尔值(true), 但不能转换为数值
  • Symbol可以设置参数对Symbol值进行描述
  1. Symbol.prototype.description:在Symbol函数创建Symbol值时,用参数添加一个描述。读取这个描述需要将 Symbol 显式转为字符串比较麻烦,后面ES2019提供了一个 Symbol 值的实例属性description,直接返回 Symbol 值的描述。
const sym =Symbol('foo');
sym.description // "foo"
  1. 作为属性名的 Symbol,不能用点运算符;在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中;Symbol 值作为属性名时,该属性还是公开属性
  2. Object.getOwnPropertySymbols(): Symbol 值作为属性名,遍历对象的时候,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()。 Object.getOwnPropertySymbols()可以获取指定对象的所有 Symbol 属性名,该方法返回当前对象的所有座用作属性名的Symbol值的数组。:,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
  3. Symbol.for(),Symbol.keyFor() :
  • Symbol.for()接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。与Symbol()不一样的是,Symbol()不会被登记()在全局中进行搜索。
  • Symbol.keyFor() :返回一个已登记的 Symbol 类型值的key
  1. 内置的 Symbol 值
  • Symbol.hasInstance: 对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
  • Symbol.isConcatSpreadable:对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。该属性默认为undefined,与设置为true时的结果一直,表示默认展开。而类似数组的则正好相反,默认不展开。
  • Symbol.species:指向一个构造函数。创建衍生对象时,会使用该属性
  • Symbol.match:对象的Symbol.match属性,指向一个函数。当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
  • Symbol.replace:对象的Symbol.replace属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值。
  • Symbol.search:对象的Symbol.search属性,指向一个方法,当该对象被String.prototype.search方法调用时,会返回该方法的返回值。
  • Symbol.split:对象的Symbol.split属性,指向一个方法,当该对象被String.prototype.split方法调用时,会返回该方法的返回值
  • Symbol.iterator:对象的Symbol.iterator属性,指向该对象的默认遍历器方法
  • Symbol.toPrimitive:对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
  • Symbol.toStringTag:对象的Symbol.toStringTag属性,指向一个方法
  • Symbol.unscopables:对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除。

三. 箭头函数

特点

  1. 箭头函数没有自己的this对象
  2. 箭头函数的this指向在定义的时候外层第一个普通函数的this(一旦确定就不再改变,除非外外层第一个普通函数的this指向改变);普通函数的this指向在执行的时候的对象:call()、apply()、bind()也不能改变其指向
  3. 被继承的外层普通函数的this指向改变,箭头函数的this指向会跟着改变
  4. 箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象) 普通函数在严格模式下,指向undefined,非严格模式下指向全局对象
  5. 箭头函数的this指向全局对象,会报arguments未声明的错误;箭头函数的this指向普通函数this时,其arguments继承于该普通函数
  6. 箭头函数不能用new 来调用,因为其没有constructor,因此不支持new target属性
  7. 箭头函数不支持重名函数参数,普通函数的函数参数支持重名

不适用情景

  1. 定义对象方法时,在对象方法中不能用箭头函数,因为对象不单独构成作用域
  2. 需要动态的this时候,如回调函数的this

注意事项

  1. 箭头函数一条语句返回对象字面量,需要加括号
  2. 箭头函数在参数和箭头之间不能换行
  3. 箭头函数的解析顺序相对||靠前

四. Promise

  1. Promise 的含义及其三种状态
  • 意义:异步编程解决方案。语法上来讲是一个对象,获取异步操作的消息。可将异步操作以同步操作的流程表达出来,避免层层嵌套
  • 三种状态:pending 、fullfilled、rejected
  • 2个特点:对象状态不受外界影响,只有异步操作的结果可以决定该对象处于哪一种状态;一旦状态改变,就不会改变
  • 3个缺点:无法取消promise,一旦新建,立即执行,无法中断;promise内部抛出的错误需要设置回调函数才能反映到外部;处于pending状态时,无法得到promise处于哪一个阶段
  1. 基本用法 创建promise实例,Promise构造函数接收一个函数作为参数,该函数有两个参数,分别为resolve,reject
const promise =newPromise(function(resolve, reject){// ... some codeif(/* 异步操作成功 */){resolve(value);}else{reject(error);}});
  • resolve:将promise状态从未完成变为成功,在异步操作成功时调用,并将异步操作结果作为参数传出去,避免回调地狱
  • reject:将promise状态从未完成变为失败,在异步操作失败时调用,并将错误作为参数传递出去
//Promise异步加载图片functionloadImageAsync(url){returnnewPromise(function(resolve, reject){const image =newImage();

    image.onload=function(){resolve(image);};

    image.onerror=function(){reject(newError('Could not load image at '+ url));};

    image.src = url;});}
  1. Promise.prototype.then()
  • 该方法接收两个参数回调函数作为参数,第一个回调函数在Promise对象状态变为resloved时调用,第二个回调函数在Promise对象变为rejected时调用,二者接收Promise对象传出的值作为参数。
  • 该方法返回的是一个新的promise实例,可用于链式编程,上一个promise实例对象得返回值为下一个then的参数
  1. Promise.prototype.catch(),为then.(null,rejection)或then.(undefined,rejection)的别名,作用与promise.then( )一致,只是参数个数不一样用于指定发生错误时的回调函数;该方法返回的是一个promise对象,后续可继续调用.then()方法;该方法中可再次抛出错误
// 写法一(注意try{}catch(){}的用法)const promise =newPromise(function(resolve, reject){try{thrownewError('test');}catch(e){reject(e);}});
promise.catch(function(error){
  console.log(error);});// 写法二const promise =newPromise(function(resolve, reject){reject(newError('test'));});
promise.catch(function(error){
  console.log(error);});

(1)可捕获的错误有:Promise对象状态变为rejected时抛出的错误;.then()方法抛出的错误
(2)Promise错误特性:

  • 若promise状态变为resolved,则错误无法被捕获
  • Promise对象错误具有冒泡性质,会一直向后传递,直至被捕获
  • Promise错误若无catch()指定处理错误的回调函数,则不会将错误传递出去,不影响promise外的代码,外层代码没有反应
  • try{ } catch{ } 两个成对出现,前一个允许定义在执行时进行错误测试的代码块?,
  • catch用于在try代码块发生错误时进行捕获
  • finally{ }不论前面的 try{}与catch{}是否产生异常都会执行代码
  • throw { }用于抛出(创建)错误,可放在try{}内部,自定义错误
  1. **Promise.prototype.finally()**:指定不管promise对象最后状态如何,都会执行的操作
  • 该方法不接受任何参数,表明finally方法的回调函数与前面promise的状态无关,其本质为then方法的特例
  • 总会返回原来的值
  1. Promise.all(), 将多个promise实例a,b,c….(若abc…不是实例,则首先调用resolve()方法)包装成一个新的Promise实例p,其参数可以不是数组,但必须具有iterator接口。
const p = Promise.all([p1, p2, p3]);
  • 实例a b c …的状态都变成了fulfilled,p才会fulfilled,abc…的返回值组成一个数组传递给p的回调函数
  • 实例 a b c…中有一个状态为rejected,p 都为rejected,第一个a的返回值会传递给p的回调函数
  • 实例a b c … 有自己的catch()方法,则一旦这些实例的状态为rejected,则仅触发自己的catch,而不会触发promise.all()的catch(),因为等所有的catch()方法调用后,实例的状态已经变成了resolved,promise.all()的catch()方法无法捕获错误
  1. **Promise.race()**方法将多个promise实例abc…包装成一个新的Promise实例p,各个子实例中,谁先改变状态,p的状态会跟着改变,并且将先改变状态的实例的返回值传递给p
  2. **Promise.allSettled()**方法(ES2020引进)接收一个数组作为参数,数组每个成员都为一个Promise对象
  • 该方法返回一个新的Promise对象,只有数组内所有成员的状态变更(不论是fulfilled还是rejected),返回的新的Promise对象的状态才会发生变更,且变更的状态皆为fulfilled
  • 其.then()方法中的回调函数会接收一个数组作为参数,该数组的每个成员对应前面数组的每个promise对象
  1. **Promise.any()**方法将多个promise实例abc…包装成一个新的Promise实例P
  • 实例a b c …的状态都变成了rejected,p才会rejected
  • 只要有一个为fulfilled,则p的状态为fulfilled,abc…的返回值组成一个数组传递给p的回调函数
  • Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。
  1. Promise.resolve(),将现有对象转为Promise对象 该方法参数分类
  • Promise实例:原封不动返回该promise对象实例
  • thenable 对象 :指具有then方法的对象,将该对象转为Promise对象,然后立即执行thenable方法的.then()方法
  • 不是thenable对象,或者根本不是对象:返回一个状态为resolved的promise对象
  • 不带任何参数:直接返回一个状态为resolved的promise对象 注:立即resolve()的Promise对象,是在本轮“事件循环event loop ”的结束时执行,而非在下一轮事件循环开始时执行。
  1. **Promise.reject()**返回一个promise实例,状态为rejected
  • Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
  1. Promise对象的应用
  • 图片加载、发送异步请求 手写代码
  • 与Generator函数相结合
  • 不论函数是异步或者同步,使用then()方法指定下一流程,用catch()处理抛出的错误
Promise.resolve().then(f)
  1. 手写promise
//创建一个Promise的类classPromise{constructor(executer){//构造函数constructor里面是个执行器this.status ='pending';//默认的状态 pendingthis.value =undefined//成功的值默认undefinedthis.reason =undefined//失败的值默认undefined//状态只有在pending时候才能改变letresolveFn=value=>{//判断只有等待时才能resolve成功if(this.status == pending){this.status ='resolve';this.value = value;}}//判断只有等待时才能reject失败letrejectFn=reason=>{if(this.status == pending){this.status ='reject';this.reason = reason;}}try{//把resolve和reject两个函数传给执行器executerexecuter(resolve,reject);}catch(e){reject(e);//失败的话进catch}}then(onFufilled,onReject){//如果状态成功调用onFufilledif(this.status ='resolve'){onFufilled(this.value);}//如果状态失败调用onRejectif(this.status ='reject'){onReject(this.reason);}}}

Set

新的数据结构,类似于数组,但成员的值都是唯一的,实现iterator接口,所以可使用扩展运算符与for…of…进行遍历
Set构造函数可用任一具有iterator接口的数据作为参数生成Set结构
特点
1.向Set中加入值时,不会发生类型转换,内部判断方法类似于 严格相等===,
但是=== 与==中,NaN不等于自身,Set中等于自身
2.Array.from()将Set结构转为数组,可用于数组去重
set的属性与方法:
1.size 返回集合元素与个数
2. add 增加新元素并返回新集合
3. delete 删除元素,返回布尔值
4. has 检测集合中是否包含某个元素,返回布尔值
5. clear 清空集合,返回undefined
6. 四个遍历方法:
(1) Set.prototype.keys():返回键名的遍历器 注:Set的键名与键值相同
(2)Set.prototype.values():返回键值的遍历器
(3)Set.prototype.entries():返回键值对的遍历器
(4)Set.prototype.forEach():使用回调函数遍历每个成员

//声明一个 setlet s =newSet();let s2 =newSet(['大事儿','小事儿','好事儿','坏事儿','小事儿']);//元素个数// console.log(s2.size);//添加新的元素// s2.add('喜事儿');//删除元素// s2.delete('坏事儿');//检测// console.log(s2.has('糟心事'));//清空// s2.clear();// console.log(s2);for(let v of s2){
            console.log(v);}

集合操作:

let arr1 =[1,2,3,4,5,4,3,2,1];//1. 数组去重let result1 =[...newSet(arr)];
        console.log(result1);//2. 交集let arr2 =[4,5,6,5,6];let result2 =[...newSet(arr1)].filter(item=>{let s2 =newSet(arr2);// 4 5 6if(s2.has(item)){returntrue;}else{returnfalse;}});//简化写法 let result22 =[...newSet(arr1)].filter(item=>newSet(arr2).has(item));
         console.log(result);//3. 并集let union =[...newSet([...arr,...arr2])];
         console.log(union);//4. 差集let diff =[...newSet(arr1)].filter(item=>!(newSet(arr2).has(item)));
        console.log(diff);

weakSet

与Set类似,也是不重复的值的集合,
与Set不同的点:该数据结构成员只能是对象,而不能是其他类型的值;该数据结构中的对象为弱引用,即垃圾回收机制不考虑weakSet对该对象的引用,该结构只适用于存放临时对象及其信息,不适合被引用,该结构不可被遍历
三个方法
WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例中
WeakSet 没有size属性,没有办法遍历它的成员。

Map

它类似于对象,也是键值对的集合。但是“键”范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用扩展运算符和for…of…进行遍历。对同一个键进行多次赋值,后面的值将覆盖前面的值。Map的键读取的是该值的内存地址,只要两个值严格相等,则将其视为同一个键。(NaN例外,虽然NaN与自身不严格相等,但Map会当成同一个键)
Map 的属性和方法:
1.size() 返回集合Map个数

  1. set ()增加新元素并返回当前map,可用链式写法
  2. get ()返回键名对象的键值
  3. has() 检测map中是否包含某个元素,返回布尔值
  4. clear() 清空集合,返回undefined
  5. delete()清空某个元素,返回布尔值
  6. map.forEach,实现遍历
//声明 Maplet m =newMap();//添加元素
        m.set('name','尚硅谷');
        m.set('change',function(){
            console.log("我们可以改变你!!");});let key ={school:'ATGUIGU'};
        m.set(key,['北京','上海','深圳']);//size
        console.log(m.size);//删除
         m.delete('name');//获取
         console.log(m.get('change'));
         console.log(m.get(key));//清空
         m.clear();//遍历for(let v of m){
            console.log(v);}/*与其他数据结构相互转换*///转换为数组 ...扩展运算符const myMap =newMap().set(true,7).set({foo:3},['abc']);[...myMap]//数组转为MapnewMap([[true,7],[{foo:3},['abc']]])//Map转为对象functionstrMapToObj(strMap){let obj = Object.create(null);for(let[k,v]of strMap){
            obj[k]= v;}return obj;}const myMap =newMap().set('yes',true).set('no',false);strMapToObj(myMap)//对象转为Map Object.entries()或者自己构造转换函数let obj ={"a":1,"b":2};let map =newMap(Object.entries(obj))//Map转为JSON//(1)Map 的键名都是字符串,这时可以选择转为对象 JSON。functionstrMapToJson(strMap){returnJSON.stringify(strMapToObj(strMap));}let myMap =newMap().set('yes',true).set('no',false);strMapToJson(myMap)//(2)Map 的键名有非字符串,这时可以选择转为数组 JSONfunctionmapToArrayJson(map){returnJSON.stringify([...map]);}let myMap =newMap().set(true,7).set({foo:3},['abc']);mapToArrayJson(myMap)

WeakMap

与Map结构相似,用于生成键值对的集合
区别:
(1) WeakMap只接受对象作为键名(null除外),其键名所指向的对象,不计入垃圾回收机制,与WeakSet类似,WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。
(2) 没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性。不支持clear()
属性与方法:get()、set()、has()、delete()。
用途: DOM 节点作为键名;部署私有属性

WeakRef

WeakRef() 构造函数直接创建对象的弱引用(创建对象)
WeakRef实例对象有方法:deref()
作用:作为缓存,未被清除时可以从缓存取值,一旦清除缓存就自动失效。

Iterator与for…of循环

Iterator

  1. Iterator作用:为各种数据结构,提供统一的访问接口;使数据结构成员按某种顺序排列;for…of循环
  2. iterator的next方法:调用一次,返回value与done,前者是当前成员的值,done是一个布尔值,表示遍历是否结束
  • 模拟遍历器next方法
var it =makeIterator(['a','b']);

it.next()// { value: "a", done: false }
it.next()// { value: "b", done: false }
it.next()// { value: undefined, done: true }functionmakeIterator(array){var nextIndex =0;return{next:function(){return nextIndex < array.length ?{value: array[nextIndex++],done:false}:{value:undefined,done:true};}};}
  1. symbol.iterator:数据结构的一个属性,执行该属性会返回一个遍历器对象,即为数据结构部署接口
  2. 原生具备遍历器接口的:Array、Map、Set、String、TypedArray、arguments对象、NodeList对象。其余数据结构的iterator接口需要手动部署
  3. 使用场合:
  • 解构赋值
  • 扩展运算符
  • yiled
  • 数组的遍历
  1. return()、throw()方法

for…of循环

  1. for…in… 获得键名
  2. for…of…获得键名
  3. entries()返回键名-键值对对象
  4. keys()返回键值对象
  5. forEach

Generator

  1. 基本概念:一种异步编程解决方案,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数,返回的遍历器对象,可以依次遍历Generator 函数内部的每一个状态
  • function关键字与函数名之间有一个星号*
  • 函数体内部使用yield表达式,定义不同的内部状态,yiled表达式是暂停执行的标志;当调用遍历器对象的next()方法时,遇到yiled表达式就暂停后续操作,并将该yiled后面的表达式的值,作为返回的对象的value属性值
  • yiled与return的联系都能返回紧跟在语句后面的那个表达式的值,区别在于遇到yiled暂停执行,下一次继续从该位置执行。而return不具备位置记忆功能,一个return 只能执行一次,yiled可以执行多次
  • yile表达式只能用在generator函数里面,其余地方会报错
  1. generator 与 iterator的联系
  • 对象的Symbol.iterator方法为遍历器生成函数,generator也是遍历器生成函数,因此将Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口
  • generator函数执行后,会返回一个遍历器对象,改遍历器对象本身的symbol.iterator属性也是遍历器对象生成函数,执行后返回自身这个遍历器对象
  1. next方法参数:yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
  2. for…of 循环:for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。因此,可通过generator函数为原生对象添加接口。或将generator函数加到对象的symbol.iterator属性上,使得对象可以遍历
  3. Generator.prototype.throw()方法:Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获
  4. Generator.prototype.return()方法:Generator 函数返回的遍历器对象,有return()方法,可以返回给定的值,并且终结遍历 Generator 函数
  5. yield* 表达式 : Generator 函数内部,调用另一个 Generator 函数。需要在前者的函数体内部,自己手动完成遍历,而ES6提供的yield*表达式可以实现在一个generator函数里自动调用另一个generator函数
  • yield命令可以进行数组打平 手写代码
function*iterTree(tree){if(Array.isArray(tree)){for(let i=0; i < tree.length; i++){yield*iterTree(tree[i]);}}else{yield tree;}}const tree =['a',['b','c'],['d','e']];
  1. Generator函数的this: 函数总是返回一个遍历器,这个遍历器是生成器函数的实例,同样继承生成器函数的prototype上的方法。
  • 不能将生成器函数当成普通的构造函数,如果将其当成普通的构造函数,其返回的遍历器对象不能获取其内部的this对象(个人理解为,生成器函数与构造函数的概念互斥)
  • 不能使用new 命令来调用生成器函数

Async与Await

async本质为Generaor函数的语法糖:async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已

  1. async 对 Generator函数的改进:
  • 内置执行器:Generator 函数的执行必须靠执行器,即必须调用next方法,而async函数有内置的执行器,与普通函数调用一致
  • 语义更清晰:async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
  • 更广的适用性:yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(虽然是原始类型的值,但会立马被转换为resolved的promise对象)
  • 返回值:async函数的返回值是 Promise 对象,Generator 函数的返回值是 Iterator 对象,返回的Promise对象比Iterator对象方便很多,可使用.then方法指定下一步的操作
  1. async语法
  • async函数返回一个promise对象:该函数async内部return语句返回的值,会成为then方法回调函数的参数;函数内部抛出的错误也会导致返回的promise对象变为rejected状态,抛出的错误会被catch方法回调函数接收到
  • promise对象状态变化:内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误
  1. await命令:一般情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值;特殊情况下,await命令后面是一个thenable对象(即定义了then方法的对象),那么await会将其等同于 Promise 对象
  • 错误处理:若await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject;想要防止错误影响后续的函数调用,则将await命令放在try{ }catch(e){ }中注意:await后面的promise对象状态若为rejected,会影响后续函数调用,可放在try{ }模块中;多个await后面的异步操作,若不存在继发关系,最好使其同时触发;await只能用在async函数中
  1. async函数的实现原理:Generator 函数和自动执行器,包装在一个函数里。
  2. 顶层await:早期的语法规定,await函数只能出现在async函数内部

FinalizationRegistry

清理注册表功能

Proxy

用于修改某些操作默认行为,属于元编程
Proxy(target,handler)构造函数,用来生Proxy实例,target为拦截目标对象,handler为定制拦截行为的对象(操作)

  1. handler 若没设置任何拦截,则proxy实例就等于被代理的对象
  2. 将proxy设置为对象的属性,则可以通过调用对象属性使用 将proxy作为另一对象的原型对象,也会调用
  3. Proxy支持的常见拦截操作: (1)get(target, propKey, receiver):拦截对象属性的读取,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选,最后一个参数总是指向原始的读操作所在的那个对象,一般情况下就是 Proxy 实例。:如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。 (2)set(target, propKey, value, receiver):拦截对象属性的赋值操作,四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。:如果一个属性不可写(writable),则 set方法不起作用;set代理应当返回一个布尔值。严格模式下,set代理如果没有返回true,就会报错。 (3)has(target, propKey):拦截propKey in proxy的操作(拦截的是HasProperty操作),两个参数,目标对象、需查询的属性名:若某属性不可配置或目标对象不可扩展,则不得使用has方法进行拦截,会报错;该拦截只对in运算符生效,对for…in循环不生效 (4)**ownKeys(target)**:拦截Object.getOwnPropertyNames(proxy)、 Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 (5)**getOwnPropertyDescriptor(target, propKey)**:拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象或undefined (6)**getPrototypeOf(target)**:拦截Object.getPrototypeOf(proxy),拦截获取对象原型 (7) setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值 (8) apply(target,contex,args):拦截函数的调用、call、apply,三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。 (9) construct(target,args,new Target) 方法用于拦截new命令, 三个参数,目标对象(需是函数),构造函数的参数数组,用new创建实例对象时new命令作用的构造函数。 该方法返回的必须是对象,否则报错;拦截的目标对象是函数;
const handler ={construct(target, args, newTarget){returnnewtarget(...args);}};

(10) deleteProperty() ,拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除
(11) defineProperty(),拦截了Object.defineProperty()操作。
:,如果目标对象不可扩展(non-extensible),则defineProperty()不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则defineProperty()方法不得改变这两个设置。
(12)
preventExtensions()
拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。只有目标对象不可扩展时(即Object.isExtensible(proxy)为false proxy.preventExtensions 才能返回true,否则会报错。
(13)this的指向,proxy代理的情况下,this指向proxy代理。
应用:代理服务器

Reflect

将Object对象的一些明显属于语言内部的方法,放在Reflect对象上;修改某些Object方法的返回结果,让其变得更合理; 让Object操作都变成函数行为;Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法
(1)静态方法:13个静态方法,与Proxy一一对应
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)

a. 若name属性设置了赋值set、读取get函数,则赋值/读取函数的this指向receiver
b.如果 Proxy对象和 Reflect对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为,而且传入了receiver,那么Reflect.set会触发Proxy.defineProperty拦截。
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
(2)应用:使用 Proxy 实现观察者模式

const queuedObservers =newSet();constobserve=fn=> queuedObservers.add(fn);constobservable=obj=>newProxy(obj,{set});functionset(target, key, value, receiver){const result = Reflect.set(target, key, value, receiver);
  queuedObservers.forEach(observer=>observer());return result;}

Class

作为对象的模板,通过class关键字,可以定义类
class 实例:

//classclassShouji{//构造方法 名字不能修改constructor(brand, price){this.brand = brand;this.price = price;}//方法必须使用该语法, 不能使用 ES5 的对象完整形式call(){
                console.log("我可以打电话!!");}}let onePlus =newShouji("1+",1999);

        console.log(onePlus);

关键点:

  1. Object.assign(),一次向类添加多个方法
  2. 类内部定义的方法不可枚举
  3. constructor()是类的默认方法,创建实例时调用,默认返回类的实例
  4. 类必须使用new 关键字调用
  5. 与ES5相同,使用get、set关键字进行属性存取拦截
  6. 类的属性名,可以用表达式
  7. 严格模式
  8. 类不存在变量提升
  9. static:类的静态static成员的属性或者方法不能被实例对象访问(类似于函数对象的属性与方法不能被实例对象访问)注:静态方法中的this指向类,而非实例;ES2022中引入了静态块(static块)在类生成时运行对静态属性进行初始化
classPhone{//静态属性static name ='手机';staticchange(){
                console.log("我可以改变世界");}}let nokia =newPhone();
        console.log(nokia.name);//输出为undefined
        console.log(Phone.name);//输出为手机
  1. 实例属性可以写在constructor()方法中,也可以写在类的最顶层
  2. 私有属性(方法):在类中定义时使用#关键字,将方法(属性)设置为私有,外部无法访问,只能在类内部访问;可以将私有属性设置为静态属性static #;子类可以继承私有属性,但通过Object.creat()或Object.setPrototype()不可以继承私有属性 (1)try…catch结构可以用来判断是否存在某个私有属性。
classA{use(obj){try{
      obj.#foo;}catch{// 私有属性 #foo 不存在}}}const a =newA();
a.use(a);// 报错

(2) in运算符也可以判断是否有私有属性(对于Object.Create()、Object.setPrototypeof()形成的继承是无效的,因为这两种继承无法传递私有属性)

classA{use(obj){if(#foo in obj){// 私有属性 #foo 存在}else{// 私有属性 #foo 不存在}}}
  1. new.target属性:new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数;子类继承父类时,new.target返回子类
  2. 类的继承: (1)extends关键字继承父类方法与属性、super关键字(必须在constructor使用,先继承,后实例,只有调用super后,才可以使用this关键字)调用父类的方法与属性,constructor定义类的构造函数并初始化 (2)子类的实例也是父类的实例 (3)除私有属性外,父类所有方法与属性子类都继承(包括静态方法) (4)Object.getPrototypeOf()方法可以用来从子类上获取父类。
  3. super关键字,即可当做函数使用,也可当做对象使用(需显示指定为哪种类型) (1)做函数调用:代表父类的构造函数,子类的构造函数必须执行一次super函数,返回的是子类的实例;只能用于子类构造函数之中 (2)做对象:在普通方法中,指向父类的原型对象;在静态方法中,指向父类 普通方法中:子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例;由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性(普通——super父类原型对象——this指向子类实例) 静态方法中:在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例(静态——super父类——this指向子类)
classPhone{//构造方法constructor(brand, price){this.brand = brand;this.price = price;}//父类的成员属性call(){
                console.log("我可以打电话!!");}}classSmartPhoneextendsPhone{//构造方法constructor(brand, price, color, size){super(brand, price);// Phone.call(this, brand, price)this.color = color;this.size = size;}photo(){
                console.log("拍照");}playGame(){
                console.log("玩游戏");}call(){
                console.log('我可以进行视频通话');}}const xiaomi =newSmartPhone('小米',799,'黑色','4.7inch');// console.log(xiaomi);xiaomi.call();
        xiaomi.photo();
        xiaomi.playGame();
  1. 特殊的get与set属性,可以在父类中设置这两个属性,子类可以直接调用
// get 和 set  classPhone{getprice(){
                console.log("价格属性被读取了");return'iloveyou';}setprice(newVal){
                console.log('价格属性被修改了');}}//实例化对象let s =newPhone();// console.log(s.price);
        s.price ='free';
  1. 类的 prototype 属性和__proto__属性 (1)子类.proto === 父类 (2)子类.prototype.proto === 父类.prototype
classA{}classBextendsA{}B.__proto__ ===A// trueB.prototype.__proto__ ===A.prototype // true
  1. 实例的_proto_属性 子类.__ proto __ . __ proto __ === 父类.proto 子类.__ proto__.__proto__可以修改父类实例的行为
  2. 原生构造函数的继承 原生构造函数通常用来生成数据结构,是无法继承的 Boolean() Number() String() Array() Date() Function() RegExp() Error() Object()

数值扩展

Number.EPSILON 是 JavaScript 表示的最小精度
二进制(0b)与八进制(0o)
Number.isFinite( )检测数值是否为有限
Number.isNaN( )检测一个数值是否为NaN
Number.parseInt( )将字符串提取为整数
Number.parseFloat( )将字符串提取为浮点数
Number.isInteger( ) 判断一个数是否为整数
Math.sign 判断一个数到底为正数 负数 还是零
Math.trunc( ) 去除小数部分,返回整数部分

//0. Number.EPSILON 是 JavaScript 表示的最小精度EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16// function equal(a, b){//     if(Math.abs(a-b) < Number.EPSILON){//         return true;//     }else{//         return false;//     }// }// console.log(0.1 + 0.2 === 0.3);// console.log(equal(0.1 + 0.2, 0.3))//1. 二进制和八进制let b =0b1010;// let o = 0o777;// let d = 100;// let x = 0xff;// console.log(x);//2. Number.isFinite  检测一个数值是否为有限数
         console.log(Number.isFinite(100));// console.log(Number.isFinite(100/0));// console.log(Number.isFinite(Infinity));//3. Number.isNaN 检测一个数值是否为 NaN 
         console.log(Number.isNaN(123));//4. Number.parseInt Number.parseFloat字符串转整数
         console.log(Number.parseInt('5211314love'));// console.log(Number.parseFloat('3.1415926神奇'));//5. Number.isInteger 判断一个数是否为整数
         console.log(Number.isInteger(5));// console.log(Number.isInteger(2.5));//6. Math.trunc 将数字的小数部分抹掉  
        console.log(Math.trunc(3.5));//7. Math.sign 判断一个数到底为正数 负数 还是零
        console.log(Math.sign(100));
        console.log(Math.sign(0));
        console.log(Math.sign(-20000));

对象方法扩展

1.Object.is(a, b) 判断a,b两个值是否完全相等, 与===不同之处可以比较NaN
2.Object.assign(obj1, obj2) 对象的合并(实际为obj2将obj1覆盖)
3. Object.setPrototypeOf (obj1,obj2)设置原型对象(将obj2设置为obj1的原型对象)

//1. Object.is 判断两个值是否完全相等 
        console.log(Object.is(120,120));//  
        console.log(Object.is(NaN,NaN));// 
        console.log(NaN===NaN);// //2. Object.assign 对象的合并const config1 ={host:'localhost',port:3306,name:'root',pass:'root',test:'test'};const config2 ={host:'http://atguigu.com',port:33060,name:'atguigu.com',pass:'iloveyou',test2:'test2'}// console.log(Object.assign(config1, config2));//3. Object.setPrototypeOf 设置原型对象  Object.getPrototypeofconst school ={name:'尚硅谷'}const cities ={xiaoqu:['北京','上海','深圳']}
        Object.setPrototypeOf(school, cities);
        console.log(Object.getPrototypeOf(school));
        console.log(school);

模块化

优势:防止命名冲突;代码复用;高维护性
模块化语法:

  1. export 用于暴露模块 分别暴露:在每个对象前面使用export暴露 统一暴露:export{要暴露的模块,,,,} 直接暴露:export default{ 要暴露的数据} 对应的导入后调用时:模块名.defalut.方法(属性名)
  2. import用于导入模块:(在编译阶段就导入了) 统一引入:import * as 文件名(去除扩展名) from “路径” 解构赋值:import {对象(内容)1, 对象(内容)2,…} from “路径” import 命令具有提升效果
  3. export与import的复合写法 表示在一个模块中,先输入后输出同一个模块,相当于对外转发了这个模块,导致当前模块不能直接使用引入输出的模块
  4. 模块的继承
//2. 解构赋值形式import{school, teach}from"./src/js/m1.js";// 当导入时有两个相同的内容名,使用别名import{school as guigu, findJob}from"./src/js/m2.js";//对于直接暴露的内容的引入,有相同的内容名,也使用别名import{defaultas m3}from"./src/js/m3.js";

直接引入(针对直接暴露):import 文件名(去除扩展名)from “路径”
模块引入的另一种方法
a.建立单独的js文件,将所有需要引入的模块在这个文件中引入
b.再在真正需要引入模块的文件里将1建立的js文件用src方法引入

//需要设置类型<script src="./src/js/app.js" type="module"></script>

Babel的使用(主要是解决兼容性问题):
5. 安装工具 npm i babel-cli babel-preset-env browserify(webpack) -D
6. 编译 npx babel src/js -d dist/js --presets=babel-preset-env
7. 打包 npx browserify dist/js/app.js -o dist/bundle.js

ES7新特性

Array.prototype.includes用来检测数组中是否包含某个元素,返回布尔类型值

const mingzhu =['西游记','红楼梦','三国演义','水浒传'];//判断
         console.log(mingzhu.includes('西游记'));//输出true
         console.log(mingzhu.includes('金瓶梅'));

**为指数运算符 用来实现幂运算,与Math.pow功能一致

// **
    console.log(2**10);// 
    console.log(Math.pow(2,10));

ES8新特性

1.async(与then类似)

async 函数的返回值为 promise 对象
若返回结果不是promise: 该函数的返回值除了主动抛出错误(此时为rejected),其余情况下返回值都是resolved Promise对象,即此时返回的promise对象无论如何都成功
若返回结果为promise: 则返回值promise对象的成功与否取决于返回结果promise的成功

2.await

await 必须写在 async 函数中
await 右侧的表达式一般为 promise 对象
await 返回的是 promise 成功的值
await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
.async 与await相结合可以使异步类似于同步???(没理解)
案例:async与await结合进行读取数据

//1. 引入 fs 模块const fs =require("fs");//读取『为学』functionreadWeiXue(){returnnewPromise((resolve, reject)=>{
        fs.readFile("./resources/为学.md",(err, data)=>{//如果失败if(err)reject(err);//如果成功resolve(data);})})}functionreadChaYangShi(){returnnewPromise((resolve, reject)=>{
        fs.readFile("./resources/插秧诗.md",(err, data)=>{//如果失败if(err)reject(err);//如果成功resolve(data);})})}functionreadGuanShu(){returnnewPromise((resolve, reject)=>{
        fs.readFile("./resources/观书有感.md",(err, data)=>{//如果失败if(err)reject(err);//如果成功resolve(data);})})}//声明一个 async 函数asyncfunctionmain(){//获取为学内容let weixue =awaitreadWeiXue();//获取插秧诗内容let chayang =awaitreadChaYangShi();// 获取观书有感let guanshu =awaitreadGuanShu();

    console.log(weixue.toString());
    console.log(chayang.toString());
    console.log(guanshu.toString());}main();

案例2:async与awit结合进行封装ajax请求

// 发送 AJAX 请求, 返回的结果是 Promise 对象functionsendAJAX(url){returnnewPromise((resolve, reject)=>{//1. 创建对象const x =newXMLHttpRequest();//2. 初始化
                x.open('GET', url);//3. 发送
                x.send();//4. 事件绑定
                x.onreadystatechange=function(){if(x.readyState ===4){if(x.status >=200&& x.status <300){//成功啦resolve(x.response);}else{//如果失败reject(x.status);}}}})}//promise then 方法测试// sendAJAX("https://api.apiopen.top/getJoke").then(value=>{//     console.log(value);// }, reason=>{})// async 与 await 测试  axiosasyncfunctionmain(){//发送 AJAX 请求let result =awaitsendAJAX("https://api.apiopen.top/getJoke");//再次测试let tianqi =awaitsendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')

            console.log(tianqi);}main();

3.Object.values( ) Object.entries( ) Object.getOwnPropertyDescriptors( )

Object.keys()方法返回一个给定对象的所有可枚举键值的数组
Object.values()方法返回一个给定对象的所有可枚举属性值的数组
Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组,返回数组的每个元素又是一个数组
Object.getOwnPropertyDescriptors()方法返回一个给定对象自身可遍历属性的描述对象

const school ={name:"尚硅谷",cities:['北京','上海','深圳'],xueke:['前端','Java','大数据','运维']};//获取对象所有的键
        console.log(Object.keys(school));//获取对象所有的值
        console.log(Object.values(school));//entries
        console.log(Object.entries(school));//创建 Mapconst m =newMap(Object.entries(school));
        console.log(m.get('cities'));

ES9

rest 参数与 spread 扩展运算符

rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符

ript>//rest 参数functionconnect({host, port,...user}){
            console.log(host);
            console.log(port);
            console.log(user);}//此时输出为host: '127.0.0.1',//port: 3306,//user:   username: 'root',password: 'root',type: 'master'connect({host:'127.0.0.1',port:3306,username:'root',password:'root',type:'master'});//对象合并const skillOne ={q:'天音波'}const skillTwo ={w:'金钟罩'}const skillThree ={e:'天雷破'}const skillFour ={r:'猛龙摆尾'}const mangseng ={...skillOne,...skillTwo,...skillThree,...skillFour};

        console.log(mangseng)

正则命名分组

便于数据的捕获,实际相当于给没项正则匹配的数据命名(用该命名来存储)

//通用方法//声明一个字符串// let str = '<a href="http://www.atguigu.com">尚硅谷</a>';// //提取 url 与 『标签文本』// const reg = /<a href="(.*)">(.*)<\/a>/;// //执行// const result = reg.exec(str);

         console.log(result);//此时输出的对象里group值为undefined
         console.log(result[1]);//输出等于console.log(result.groups.url)
         console.log(result[2]);//同上let str ='<a href="http://www.atguigu.com">尚硅谷</a>';//分组命名const reg =/<a href="(?<url>.*)">(?<text>.*)<\/a>/;const result = reg.exec(str);

        console.log(result.groups.url);

        console.log(result.groups.text);

正则反向断言

//声明字符串let str ='JS5211314你知道么555啦啦啦';//正向断言const reg =/\d+(?=啦)/;const result = reg.exec(str);//反向断言const reg =/(?<=么)\d+/;const result = reg.exec(str);
        console.log(result);

正则扩展-dotAll模式

/dot . 元字符 除换行符以外的任意单个字符

let str =`
        <ul>
            <li>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;//一般的提取方法;声明正则,?为懒惰匹配,阻止继续后面匹配// const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;//dotAll模式 gs为全局匹配const reg =/<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;//执行匹配// const result = reg.exec(str);let result;let data =[];while(result = reg.exec(str)){
            data.push({title: result[1],time: result[2]});}//输出结果
        console.log(data);

ES10

数组方法Object.fromEntries( )

Object.fromEntries()将二维数组转换成对象,是Object.Entries()(将对象转换成二维数组)的逆运算

字符串方法 trimStart trimEnd

trim()本来用作去除字符串中的空字符串
trimStart() trimEnd()用作从(左侧)(右侧)位置剔除空字符串

let str ='   iloveyou   ';
        console.log(str);
        console.log(str.trimStart());//输出 iloveyou     
        console.log(str.trimEnd());//输出      iloveyou

数组方法flat()flatMap()

flat(n)方法将数组降维,参数n为深度(相当于展开层数),默认为1
flatMap()相当于是flat 与 map的结合

Symbol.prototype.description属性

该属性输出symbol的描述符字符串

//创建 Symbollet s =Symbol('尚硅谷');

        console.log(s.description);//输出为尚硅谷

ES11

私有属性:#属性名

案例:私有属性的设置与调用

classPerson{//公有属性
            name;//私有属性#
            #age;
            #weight;//构造方法constructor(name, age, weight){this.name = name;this.#age = age;this.#weight = weight;}intro(){
                console.log(this.name);
                console.log(this.#age);
                console.log(this.#weight);}}//实例化const girl =newPerson('晓红',18,'45kg');//下列方法无法成功,不能用平常方法查看私有属性// console.log(girl.name);// console.log(girl.#age);// console.log(girl.#weight);

        girl.intro();

Promise.allSettled()方法

Promise.allSettled返回值为promise对象,该promise的结果为成功,并且值为数组,每个数组成功的值为每个调用的promise对象的状态与值
Promise.all( )与之类似,区别在于返回的状态与值promise对象的值取决于调用的promise对象的返回值(失败值)

//声明两个promise对象const p1 =newPromise((resolve, reject)=>{setTimeout(()=>{resolve('商品数据 - 1');},1000)});const p2 =newPromise((resolve, reject)=>{setTimeout(()=>{resolve('商品数据 - 2');// reject('出错啦!');},1000)});//调用 allsettled 方法// const result = Promise.allSettled([p1, p2]);const res = Promise.all([p1, p2]);

        console.log(res);

String.matchAll()方法

数据批量匹配方法

let str =`<ul>
            <li>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;//声明正则const reg =/<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg//调用方法,一次性匹配字符串里符合正则表达式的数据const result = str.matchAll(reg);

可选链操作符 ?.

// ?.functionmain(config){// const dbHost = config && config.db && config.db.host;//不用层层做判断const dbHost = config?.db?.host;

            console.log(dbHost);}main({db:{host:'192.168.1.100',username:'root'},cache:{host:'192.168.1.200',username:'admin'}})

动态import

动态import实现懒加载

//常规静态导入// import * as m1 from "./hello.js";//获取元素const btn = document.getElementById('btn');

btn.onclick=function(){import('./hello.js').then(module=>{
        module.hello();});}

BigInt数据类型

用于大整数表示与运算

//大整形,使用方法:整数后面+n// let n = 521n;// console.log(n, typeof(n));//BigInt函数// let n = 123;
        console.log(BigInt(n));//输出123n
        console.log(BigInt(1.2));//报错//大数值运算let max = Number.MAX_SAFE_INTEGER;
        console.log(max);
        console.log(max +1);
        console.log(max +2);//输出和上面输出一致

        console.log(BigInt(max))
        console.log(BigInt(max)+BigInt(1))
        console.log(BigInt(max)+BigInt(2))//大整数只能与大整数型做运算

global.This

始终指向全局对象
ES6面试题集合1
ES6面试题集合2
ES6输入输出题


本文转载自: https://blog.csdn.net/xiamengjiaomeng/article/details/124607140
版权归原作者 xiamengjiaomeng 所有, 如有侵权,请联系我们删除。

“ES6--阮一峰版笔记”的评论:

还没有评论