一、历史
- 2011年6月es5发布,2015年6月发布es6(es2015)
- ESNext:es下一个版本
二、es6及以后新增的常用api解析
1. let和const
for(var i=0;i<=3;i++){
setTimeout(function(){
console.log(i)
},10)
}
//结果 4 4 4 4
//原因:
//1、var 定义的变量是全局的,所以全局只有一个变量i,
//2、setTimeout,下一轮事件循环的时候执行,i=4
for(var i=0;i<=3;i++){
setTimeout(function(){
console.log(i)
},10)
}
//结果 1 2 3 4
//原因:见let的特性
//除了let 的方式,还可以适用闭包自执行函数。
for(var i=0;i<=3;i++){
(function(i){
setTimeout(function(){
console.log(i)
},10)
})(i)
}
- let引用了块级作用域的概念,创建setTimeout的时候,变量i只在作用域内生效,对于循环的每一次,引用的i都是不同的。
- 变量提升的问题
- const 定义一个常量
2、箭头函数
1、指向问题
箭头函数的this: 指向箭头函数定义时所处的对象,
普通函数的this:指向它的调用者,如果没有调用者则默认指向window.
2、缩写
const arrowFn = (value)=>Number(value);
const obj = ()=>{{}} // {}
3、箭头函数不能用作构造函数的原因
构造函数:改变this指向,指到新实例
箭头函数:this是在定义的时候决定的
它们的**结果是相悖的**,所以不能用作构造函数。
3、class
class Test{
_name = '';
constructor(name){
this.name = name
}
static getFormatName(){
}
get name(){
}
set name(val){
this._name = val
}
}
const instance = new Test('duoduo')
4、模板字符串
面试题:编写一个render函数,大概实现模板字符串的功能
const year = '2021';
const month = '10';
const day = '01';
const template = '${year}-${month}-${day}';
const context = {year, month, day};
const str = render(template)(context);
console.log(str);
function render(template){
return function(context){
return template.replace(/\$\{(.*?)\}/g,(match,key)=>context[key]);
}
}
5、解构
// 数组
let [a,b,c] = [1,2,3];
// 对象
const {f1,f2} = {
f1:'11',
f2:'22',
}
解构的原理:
针对可迭代对象iterator,通过遍历按顺序获取对应的值进行赋值:
- iterator是什么?是一种接口,interface,为各种不一样的数据解构提供统一的访问机制;
- 任何数据解构只要有iterator接口;
- for of ,相当于一个遍历器,遍历数据的时候,去寻找interator,
//对象不能使用for of遍历
const obj = {name:'duoduo'};
for(let key of obj){
console.log(key) // 报错
}
- interator的作用?
1、为各种不同的数据解构提供统一的访问接口
2、数据解构按照顺序处理
3、for of 可以进行遍历
function generateInterator(array){
let nextIndex = 0;
return {
next:()=>nextIndex<array.length ? {
value:array[nextIndex++],
done:false
}:{
value:undefined,
done:true
}
}
}
const iterator = generateInterator([0,1,2])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next()) //{value:undefined,done:true}
- 可迭代对象是什么?
是iterator接口的实现;
可迭代对象存在两种协议,可迭代协议,迭代器协议;
*可迭代协议:对象必须实现iterator方法,对象或者原型上必须有一个Symbol.iterator:()=>迭代器协议
*迭代器协议:必须实现一个next方法,next方法返回的对象done value
面试题:使一个对象可以使用for of遍历?
const obj = {
count:0,
[Symbol.iterator]:()=>{
return {
next:()=>{
obj.count ++;
if(obj.count <= 10){
return {
value:obj.count,
done:false
}
}else{
return {
value:undefined,
done:true
}
}
}
}
}
}
for(let item of obj){
}
6、遍历
for in:
遍历数组的时候,特点:
- 不仅遍历当前的对象,还会遍历原型链上的;
- 不适合遍历数组
forEach
- 不会被break中断;
for of:
- 特性:会被break中断
7、object
Object.keys()
获取所有key的数组
面试题:怎么模拟实现一个Object.keys
function getObjectKeys(obj){
const result = [];
for(const key in obj){
if(obj.hasOwnProperty(key)){
result.push(key)
}
}
return result
}
Object.values()
获取所有value的数组
- Object.entries() 获取所有键值对数组
面试题:⼿写实现⼀个函数模拟Object.entries?
function getObjectEntries(obj){
const result = [];
for(const key in obj){
if(obj.hasOwnProperty(key)){
result.push([key,obj[key]])
}
}
return result;
}
Object.getOwnPropertyNames()
该方法返回一个数组,该数组对元素是obj自身拥有的枚举或者不可枚举属性名称字符串。
Object.prototype.aa = '1111';
const testData = { a: 1, b: 2 }
for (const key in testData) {
console.log(key);
}
console.log(Object.getOwnPropertyNames(testData))
// ['a','b']
Object.getOwnPropertyDescriptor
是对象属性的描述符,是一个对象。 什么是descriptor? 对象对应的属性描述符, 是⼀个对象. 包含以下属性:
- configurable。 如果为false,则任何尝试删除⽬标属性或修改属性特性(writable, configurable, enumerable)的⾏为将被⽆效化。所以通常属性都有特性时,可以把 configurable设置为true即可。
- writable 是否可写。设置成 false,则任何对该属性改写的操作都⽆效(但不会报错,严格模 式下会报错),默认false。
- enumerable。是否能在for-in循环中遍历出来或在Object.keys中列举出来。
8、get set
// vue2中的数据劫持
const obj = {}
let val = undefined;
Object.defineProperty('obj','a',{
set:function(value){
val = value
},
get:function(){
return val;
},
configurable:true
})
vue3中的数据劫持
const obj = new Proxy({},{
get:function(target,propKey){
return target[propKey]
},
set;function(target,propKey,value){
return Reflect.set(target,propKey,value)
}
})
Reflect是什么? 是js语言的一种优化 将命令式行为转为函数式行为;
9、Object.assign() 浅拷贝
类似于{...a,...b}
const newObj = Object.assign({},{
name:'niuniu',
age:11
},{
name:'duoduo'
})
console.log(newObj) {name:'duoduo',age;11}
面试题:实现一个浅拷贝
function shallowClone(source){
const target = {};
for(const i in source){
if(source.hasOwnProperty(i)){
target[i] = source[i]
}
}
return target;
}
10、promise
面试题:实现一个promise.all
function PromiseAll(promiseArray){
return new Promise(function(resolve, reject)=>{
// 判断参数类型
if(!Array.isArray(promiseArray)){
return reject(new TypeError('参数必须是函数'))
}
let counter = 0;
let promiseNum = promiseArray.length;
let resolvedArray = [];
for(let i=0;i<promiseNum;i++){
Promise.resolve(promiseArray[i])
.then((value)=>{
counter++;
resolvedArray[i] = value;
if(counter == promiseNum){
resolve(resolvedArray)
}
})
.catch(e=>reject(e))
}
})
}
面试题:实现一个promise.allSettled
返回所有promise的状态和结果
function PromiseAllSettled(promiseArray){
return new Promise((resolve, reject)=>{
if(!Array.isArray(promiseArray)){
return reject(new TypeError('参数必须是一个数组'))
}
let counter = 0;
const promiseNum = promiseArray.length;
const resolvedArray = [];
for(let i=0;i<promiseNum;i++){
Promise.resolve(promiseArray[i])
.then((value)=>{
resolvedArray[i]=>{
status:'fulfilled',
value
}
})
.catch((reason)=>{
resolvedArray[i]=>{
status:'rejected',
reason
}
})
.finally(()=>{
counter++;
if(counter === promiseNum){
resolve(resolvedArray)
}
})
}
})
}
11、数组
Array.flat(arr,deep)数组扁平化
flat() ⽅法会按照⼀个可指定的深度递归遍历数组,并将所有元素与遍历到的⼦数组中的元素 合并为⼀个新数组返回
const arr1 = [1,2,[3,4,[5]]]
arr1.flat(1) //或者Infinity
面试题:实现一个flatDeep
function flatDeep(arr, d=1){
if(d>0){
return arr.reduce((res,val)=>{
if(Array.isArray(val)){
res = res.concat(flatDeep(val,d-1))
}else{
res = res.concat(val)
}
return res;
},[])
}else{
return arr.slice();
}
}
console.log(flatDeep(arr1,Infinity))
Array.includes()
includes() ⽅法⽤来判断⼀个数组是否包含⼀个指定的值,根据情况,如果包含则返回 true, 否则返回false。
Array.find
find() ⽅法返回数组中满⾜提供的测试函数的第⼀个元素的值。否则返回 undefined。
Array.from
法从⼀个类似数组或可迭代对象创建⼀个新的,浅拷⻉的数组实例
面试题:如何把一个类数组转换成真数组?
1、Array.from
2、[...arguments]
3、Array.prototype.slice.call()
Array.from([1,2,3],x=>x+1) //[2,3,4]
12、babel的解析
1、解析
接受代码输出ast
- 词法分析
- 语法分析
2、转换
接受ast对其进行遍历,可以对节点进行添加、更新、移除等操作
3、生成
把转换过的ast生成为字符串形式的代码,并且创建source map.