JavaScript-ES7~ES8新特性常用语法使用教程

x33g5p2x  于2022-07-14 转载在 Java  
字(9.0k)|赞(0)|评价(0)|浏览(270)

因为ES6的内容太多了, 如果想学ES6的新特性, 那么可以看 http://t.csdn.cn/1bXjB 超级全, 吐血编写

ES7

includes() 数组中是否包含

includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。 使用 includes() 判断字符串和字符时是区分大小写的
语法:
arr.includes(searchElement)
arr.includes(searchElement, fromIndex)

  • element:要查找的元素
  • start:开始查找的位置。
  • 返回值: 如果数组中包含要查找的元素,则返回true,否则返回false。
  • 如果start参数小于0,则重置为0,如果start参数大于等于数组长度,则返回false。
[1,2,3].includes(2);     // true
[1,2,3].includes(2, 0);  // true
[1,2,3].includes(2, 2);  // false
[1,2,3].includes(2, 5);  // false
[1,2,3].includes(2, -1); // false

该方法与indexOf()的区别在于,indexOf()不会识别NaN和稀疏数组中的缺失元素。而includes()方法可以。

var array = [1,2,3];
    array.length = 5;
    array.push(NaN);
    array.push(undefined);
    array.push("");

    console.log( array.includes(undefined))// true
    console.log( array.includes(NaN)) // true
    console.log( array.includes("")) // true
    console.log(array.indexOf(undefined))// 6
    console.log(array.indexOf(NaN))// -1
    console.log(array.indexOf(""))// 7

指数运算符**

在ES7中引入了指数运算符,具有与Math.pow()求幂运算 等效的计算结果

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

ES8

Async/Await

我们都知道使用Promise能很好地解决回调地狱的问题,但如果处理流程比较复杂的话,那么整段代码将充斥着then,语义化不明显,代码不能很好地表示执行流程,那有没有比Promise更优雅的异步方式? ES7提出的基于Promise的解决异步的最终方案Async/Await

async

async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。因此对async修饰的函数可以直接使用then方法, 如果方法出现了异常,那么会调用catch ,注意被async修饰的方法会变为异步方法

async function fun0(){
        console.log(1);
        return 1;
    }
    fun0().then(val=>{
        console.log(val) // 1,1
    }).catch(err=>{
        console.log(err)
    })

    async function fun1(){
        console.log('Promise');
        return new Promise(function(resolve,reject){
            resolve('Promise1')
        })
    }
    fun1().then(val => {
        console.log(val); // Promise Promise
    })


    async function fun2(){
       throw  new Error("xxxxx")
    }
    fun2().then(val=>{
        console.log(val)
    }).catch(err=>{
        console.log(err) //xxxxx
    })
await

await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待 , await 修饰的如果是Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;如果不是Promise对象,比如字符串那么会把这个字符串当做await表达式的结果

使用await必须是直系(作用域链不能隔代),这样会报错:Uncaught SyntaxError: await is only valid in async function。,比如下面

let data = 'data'
demo  = async function () {
    const test = function () {
        await data //错误使用
    }
}

注意只有 let c = await new Promise ,配合才能进行等待内部执行结果,如果不是和Promise 进行配合那么await 等于无效

const demo = async ()=>{
    let result = await setTimeout(()=>{
      console.log('我延迟了一秒');
    }, 1000)
    console.log('======================');
   
}
demo() 
// 执行结果
//======================
//我延迟了一秒 
//奇怪,并没有await啊?setTimeout是异步啊,问题在哪?问题就在于setTimeout这是个异步,但是不是Promise!起不到“等待一会”的作用。
//请记住await是在等待一个Promise的异步返回

混合使用async 和await 案例

async function fun(){
        let a =  1;

        //内部使用了ajax会异步, 我们在外部使用await等待内部请求的结果
        let b = await new Promise((resolve,reject)=>{
            var ajax = new XMLHttpRequest();
            ajax.open("GET", "http://localhost:7003/test/haoxiaoxiao");
            ajax.setRequestHeader("Content-Type", "application/json");
            ajax.send({
                "userName": "卢超glrau",
                "passWord": "Y2hKz0h",
                "phone": "18110454396",
                "email": "h.whf@gjifcniah.dk"
            });
            ajax.onreadystatechange = function () {
                if (ajax.readyState == 4 && ajax.status == 200) {
                    var json = JSON.parse(ajax.responseText);
                    console.log(json)
                    resolve(json);
                }
            }
        })
         //内部使用了setTimeout会异步, 我们在外部使用await等待setTimeout内部的结果
        let c = await new Promise((resolve, reject) => {
            setTimeout(()=>{
                resolve('Promise')
            }, 1000)
        });

        let d = await function(){
            return 'function'
        }()

        console.log(a,b,c,d)
        return b;

    }
    fun();
async/await 优势实战
const setDelay = (millisecond) => {
  return new Promise((resolve, reject)=>{
      if (typeof millisecond != 'number') reject(new Error('参数必须是number类型'));
      setTimeout(()=> {
        resolve(`我延迟了${millisecond}毫秒后输出的`)
      }, millisecond)
  })
}
const setDelaySecond = (seconds) => {
  return new Promise((resolve, reject)=>{
      if (typeof seconds != 'number' || seconds > 10) reject(new Error('参数必须是number类型,并且小于等于10'));
      setTimeout(()=> {
        resolve(`我延迟了${seconds}秒后输出的,注意单位是秒`)
      }, seconds * 1000)
  })
}

比如上面两个延时函数(写在上面),比如我想先延时1秒,在延迟2秒,再延时1秒,最后输出“完成”,这个过程,如果用then的写法,大概是这样:

setDelay(1000)
.then(result=>{
    console.log(result);
    return setDelaySecond(2) //注意
})
.then(result=>{
    console.log(result);
    return setDelay(1000)  //注意
})
.then(result=>{
    console.log(result);
    console.log('完成')
})
.catch(err=>{
    console.log(err);
})

咋一看是不是挺繁琐的?如果逻辑多了估计看得更累,现在我们来试一下async/await

(async ()=>{
  const result = await setDelay(1000);
  console.log(result);
  console.log(await setDelaySecond(2));
  console.log(await setDelay(1000));
  console.log('完成了');
})()

看!是不是没有冗余的长长的链式代码,语义化也非常清楚,非常舒服,那么你看到这里,一定还发现了,上面的catch我们是不是没有在async中实现?接下去我们就分析一下async/await如何处理错误?

async/await错误处理

因为async函数返回的是一个Promise,所以我们可以在外面catch住错误。

(async ()=>{
        const result = await setDelay(1000);
        console.log(result);
        console.log(await setDelaySecond(2));
        console.log(await setDelay(1000));
        console.log('完成了');
    })().catch(err=>{
        console.log(err)
    })

// 下面这种也行

    const demo = async ()=>{
        const result = await setDelay(1000);
        console.log(result);
        console.log(await setDelaySecond(2));
        console.log(await setDelay(1000));
        console.log('完成了');
    }
    demo().catch(err=>{
        console.log(err);
    })

在async函数的catch中捕获错误,当做一个Pormise处理,同时你不想用这种方法,可以使用try…catch语句:

(async ()=>{
  try{
    const result = await setDelay(1000);
    console.log(result);
    console.log(await setDelaySecond(2));
    console.log(await setDelay(1000));
    console.log('完成了');
  } catch (e) {
    console.log(e); // 这里捕获错误
  }
})()

这时候你就不需要在外面catch了。有人会问了,我try…catch好像只能包裹代码块,如果我需要拆分开分别处理,不想因为一个的错误就整个process都crash掉了,那么难道我要写一堆try…catch吗?我就是别扭,我就是不想写try…catch怎嘛办? 我们知道await后面跟着的肯定是一个Promise那是不是可以这样写?

(async ()=>{
  const result = await setDelay(1000).catch(err=>{
      console.log(err)
  });
  console.log(result);
  const result1 = await setDelaySecond(12).catch(err=>{
      console.log(err)
  })
  console.log(result1);
  console.log(await setDelay(1000));
  console.log('完成了');
})()

是不是就算有错误,也不会影响后续的操作,是不是很棒?当然不是,你说这代码也忒丑了吧,乱七八糟的,写得别扭await又跟着catch。那么我们可以改进一下,封装一下提取错误的代码函数:

function to(promise) {
   return promise.then(data => {
      return [null, data];
   })
   .catch(err => [err]); // es6的返回写法
}
// 返回的是一个数组,第一个是错误,第二个是异步结果,使用如下:
(async ()=>{
   // es6的写法,返回一个数组(你可以改回es5的写法觉得不习惯的话),第一个是错误信息,第二个是then的异步返回数据,这里要注意一下重复变量声明可能导致问题(这里举例是全局,如果用let,const,请换变量名)。
  [err, result] = await to(setDelay(1000)) 
   // 如果err存在就是有错,不想继续执行就抛出错误
  if (err) throw new Error('出现错误,同时我不想执行了');
  console.log(result);
  [err, result1] = await to(setDelaySecond(12))
   // 还想执行就不要抛出错误
  if (err) console.log('出现错误,同时我想继续执行', err);
  console.log(result1);
  console.log(await setDelay(1000));
  console.log('完成了');
})()
async/await的中断(终止程序)

写在async/await中想要中断程序就很简单了,因为语义化非常明显,其实就和一般的function写法一样,想要中断的时候,直接return一个值就行,null,空,false都是可以的。看例子:

let count = 6;
const demo = async ()=>{
  const result = await setDelay(1000);
  console.log(result);
  const result1 = await setDelaySecond(count);
  console.log(result1);
  if (count > 5) {
      return '我退出了,下面的不进行了';
    // return; 
    // return false; // 这些写法都可以
    // return null;
  }
  console.log(await setDelay(1000));
  console.log('完成了');
};
demo().then(result=>{
  console.log(result);
})
.catch(err=>{
  console.log(err);
})

Object.values(),Object.entries()

ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。ES8引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for…of循环使用。

Object.values()

//假设我们要遍历如下对象obj的所有值:
const obj = {a: 1, b: 2, c: 3};

//不使用Object.values() :ES7
const vals=Object.keys(obj).map(key=>obj[key]);
console.log(vals);//[1, 2, 3]

//使用Object.values() :ES8
const values=Object.values(obj1);
console.log(values);//[1, 2, 3]

Object.entries()

//不使用Object.entries() :ES7
Object.keys(obj).forEach(key=>{
	console.log('key:'+key+' value:'+obj[key]);
})
//key:a value:1
//key:b value:2
//key:c value:3

//使用Object.entries() :ES8
for(let [key,value] of Object.entries(obj1)){
	console.log(`key: ${key} value:${value}`)
}
//key:a value:1
//key:b value:2
//key:c value:3

String padding

在ES8中String 新增了两个实例函数 String.prototype.padStart 和 String.prototype.padEnd,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。
ES5对String补白的方式, 例如将数字都输出成两位数,前面0补位学习

for(let i = 1 ; i < 32 ; i++){
  console.log(i >= 10 ? i : `0${i}`)
}
// 1-9输出01-09
// 10-31正常输出

padStart
用另外一个字符串填充当前字符串(若是须要的话,会重复屡次),从头补白(也就是左侧)

  • 第一个参数是目标长度,要输出的位数
  • 第二个参数是占位内容,默认是空格
  • 返回值是生成的新的字符串
for(let i = 1 ; i < 32 ; i++){
  // 目标是2位数,不够的用0补齐
  console.log(i.toString().padStart(2, '0'))
}
// 1-9输出01-09
// 10-31正常输出

padEnd
用另外一个字符串填充当前字符串(若是须要的话,会重复屡次),从当前字符串的末尾(右侧)开始填充

  • 第一个参数是目标长度,要输出的位数
  • 第二个参数是占位内容,默认是空格
  • 返回值是生成的新的字符串
for(let i = 1 ; i <= 100 ; i++){
       // 从尾部补充到指定的长度
        console.log(i.toString().padEnd(3, 'xx'))
    }
    //1xx
    //11x
    //100

函数参数列表结尾允许逗号

重新排列项目更简单,不必添加和删除逗号,最后的逗号了js自动处理。

//定义参数时
function foo(
    param1,
    param2,//结尾逗号
) {}
//传参时
foo(
    'coffe',
    '1891',//结尾逗号
);
//对象中
let obj = {
    "a": 'coffe',
    "b": '1891',//结尾逗号
};
//数组中
let arr = [
    'coffe',
    '1891',//结尾逗号
];

Object.getOwnPropertyDescriptors()

获取所有属性里面的数据描述符,只接受一个参数,目标对象。

console.log(Object.getOwnPropertyDescriptors(data))
// Portland: {value: "78/50", writable: true, enumerable: true, configurable: true}
// Dublin: {value: "88/52", writable: true, enumerable: true, configurable: true}
// Lima: {value: "58/40", writable: false, enumerable: false, configurable: true}

获取单个属性的描述符 Object.getOwnPropertyDescriptor() 这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。

返回值是一个对象:

  • 如果是访问器属性,这个对象的属性有configurable、enumerable、get和set;
  • 如果是数据属性,这个对象的属性有configurable、enumerable、writable和value。

SharedArrayBuffer对象

使用SharedArrayBuffer,两个线程的两个WebWorker都可以在同一块内存中写入数据和读取数据。这意味着它们不像postMessage那样具有通信开销和延迟。两个Web工作人员都可以立即访问到需要的数据。但是,同时从两个线程同时访问存在一定的危险。它可能导致内存中出现竞争状况。 现在游览器都禁用了SharedArrayBuffer,

Atomics对象

Atomics 对象提供了一组静态方法用来对 SharedArrayBuffer 对象进行原子操作。

点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复感谢,配合,希望我的努力对你有帮助^_^免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我。

相关文章