前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

ES6②

作者头像
ymktchic
发布2022-01-18 17:21:57
4190
发布2022-01-18 17:21:57
举报
文章被收录于专栏:ymktchicymktchic

生成器

基本概念

Generator 函数是Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

代码语言:javascript
复制
function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(helloworld),即该函数有三个状态:hello,world 和 return 语句(结束执行)。

然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)

下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

ES6没有规定,function关键字与函数名之间的星号,写在哪个位置。这导致下面的写法都能通过。

代码语言:javascript
复制
function * foo(x, y) { ··· }

function *foo(x, y) { ··· }

function* foo(x, y) { ··· }

function*foo(x, y) { ··· }

生成器函数解决回调地狱问题

要实现异步要不断的嵌套,如下。

代码语言:javascript
复制
setTimeout(()=>{
    console.log("1s")
    	setTimeout(()=>{
   	 console.log("2s")
    		 setTimeout(()=>{
   		 console.log("3s")
		},3000)
 },2000)
},1000)

这就是所谓的callback hell

解决方法

代码语言:javascript
复制
function one(){
    setTimeout(()=>{
        console.log("1s")
        iterator.next()
    },1000)
}
function two(){
    setTimeout(()=>{
        console.log("2s")
        iterator.next()
    },2000)
}
function three(){
    setTimeout(()=>{
        console.log("3s")
     
    },3000)
}
function *gen(){
    yield one();
    yield two();
    yield three();


}
var  iterator =gen()
  iterator.next()

实例2

代码语言:javascript
复制
//模拟获取  用户数据  订单数据  商品数据 
       function getUsers(){
           setTimeout(()=>{
               let data = '用户数据';
               //调用 next 方法, 并且将数据传入
               iterator.next(data);
           }, 1000);
       }
       function getOrders(){
           setTimeout(()=>{
               let data = '订单数据';
               iterator.next(data);
           }, 1000)
       }
       function getGoods(){
           setTimeout(()=>{
               let data = '商品数据';
               iterator.next(data);
           }, 1000)
       }
       function * gen(){
           let users = yield getUsers();
           let orders = yield getOrders();
           let goods = yield getGoods();
       }
       //调用生成器函数
       let iterator = gen();
       iterator.next();

promise对象

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

如果某些事件不断地反复发生,一般来说,使用stream模式是比部署Promise更好的选择。

基本使用

代码语言:javascript
复制
const p =new Promise(function(resolve,reject)
   {
      setTimeout(()=>{

       let data ='数据返回成功'
       resolve(data)
       // let err ='数据返回失败'
       // reject(err)

      },2000)
   }
   )
   p.then(function(value){
       console.log(value)

   },function(reason){
       console.log(reason)
   })

读取文件

代码语言:javascript
复制
const fs = require('fs')
// fs.readFile('aa.txt',(err,data)=>{

//     if(err) throw err;
//     console.log(data.toString())
// })
const p =new Promise(function(resolve,reject){
  fs.readFile('aa.txt',(err,data)=>{
     if (err) reject(err)
    resolve(data)
  })
})
p.then(function(value){
    console.log(value.toString())
},function(reason){
console.log("读取失败!!")

})

封装ajax

原生ajax请求

就直接往本站发请求了,看看拿不拿的到响应结果。

代码语言:javascript
复制
    const xhr = new XMLHttpRequest()
xhr.open("GET",'https://www.jnylife.com')
xhr.send()
xhr.onreadystatechange= function (){
    if(xhr.readyState ===4){
        if(xhr.status>=200 && xhr.status<= 300)
        //成功
        console.log(xhr.response)
        else{
        console.error(xhr.status)
}
    }
}

成功拿到响应结果,如图:

image-20211212154024392
image-20211212154024392

promise封装ajax

代码语言:javascript
复制
  const p  =  new Promise((resolve,reject)=>{

    const xhr = new XMLHttpRequest()
    xhr.open("GET",'https://www.jnylife.com')
    xhr.send()
    xhr.onreadystatechange= function (){

  
    if(xhr.readyState ===4){
        if(xhr.status>=200 && xhr.status<= 300)
        //成功
        resolve(xhr.response)
        else{

        reject(xhr.status)
}
    }
}
   })
    p.then(function(value){
          console.log(value)  
    },function(reason){
        console.log(reason) 
    })

Promise.prototype.then()

Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

代码语言:javascript
复制
getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

代码语言:javascript
复制
getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("Resolved: ", comments);
}, function funcB(err){
  console.log("Rejected: ", err);
});

上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为Resolved,就调用funcA,如果状态变为Rejected,就调用funcB

如果采用箭头函数,上面的代码可以写得更简洁。

代码语言:javascript
复制
getJSON("/post/1.json").then(
  post => getJSON(post.commentURL)
).then(
  comments => console.log("Resolved: ", comments),
  err => console.log("Rejected: ", err)
);

读取多个文件

代码语言:javascript
复制
//引入 fs 模块
const fs = require("fs");


//使用 promise 实现
const p = new Promise((resolve, reject) => {
    fs.readFile("aa.txt", (err, data) => {
        resolve([data]);
    });
});

p.then(value => {

    return new Promise((resolve, reject) => {
    
        fs.readFile("aa.txt", (err, data) => {
          value.push(data)
          resolve(value)
        });
    });
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("aa.txt", (err, data) => {
            //压入
            value.push(data);
            resolve(value);
        });
    })
}).then(value => {
    console.log(value.toString());
});

Set

Set本质就是集合,元素唯一。

Set结构的实例有以下属性。

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。
代码语言:javascript
复制
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
// let result = [...new Set(arr)];
// console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
// let result = [...new Set(arr)].filter(item => {
//     let s2 = new Set(arr2);// 4 5 6
//     if(s2.has(item)){
//         return true;
//     }else{
//         return false;
//     }
// });
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
// console.log(result);

//3. 并集
// let union = [...new Set([...arr, ...arr2])];
// console.log(union);

//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);

MAP

JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

代码语言:javascript
复制
var data = {};
var element = document.getElementById('myDiv');

data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"

上面代码原意是将一个DOM节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]

为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。

代码语言:javascript
复制
let m = new Map();

   //添加元素
   m.set('name','chenhao');
   m.set('change', function(){
       console.log("chenhao is cool");
   });
   console.log(m)
   let key = {
       school : 'ynnubs'
   };
   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);
   }

   // console.log(m);
image-20211212172632013
image-20211212172632013

class

JavaScript语言的传统方法是通过构造函数,定义并生成新对象。下面是一个例子。

代码语言:javascript
复制
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

上面这种写法跟传统的面向对象语言(比如C++和Java)差异很大,很容易让新学习这门语言的程序员感到困惑。

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

代码语言:javascript
复制
   //手机
   function Phone(brand, price){
    this.brand = brand;
    this.price = price;
}

//添加方法
Phone.prototype.call = function(){
    console.log("我可以打电话!!");
}

//实例化对象
let Huawei = new Phone('华为', 5999);
Huawei.call();
console.log(Huawei);

//class
class Shouji{
    //构造方法 名字不能修改
    constructor(brand, price){
        this.brand = brand;
        this.price = price;
    }

    //方法必须使用该语法, 不能使用 ES5 的对象完整形式
    call(){
        console.log("我可以打电话!!");
    }
}

let onePlus = new Shouji("1+", 1999);

console.log(onePlus);
image-20211212173734737
image-20211212173734737

利用async和await结合发送ajax请求

代码语言:javascript
复制
// 发送 AJAX 请求, 返回的结果是 Promise 对象
       function sendAJAX(url) {
           return new Promise((resolve, reject) => {
               //1. 创建对象
               const x = new XMLHttpRequest();

               //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 测试  axios
       async function main(){
           //发送 AJAX 请求
           let result = await sendAJAX("https://api.apiopen.top/getJoke");
           //再次测试
           let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')

           console.log(tianqi);
       }

       main();
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 生成器
    • 基本概念
    • 生成器函数解决回调地狱问题
      • 解决方法
        • 实例2
        • promise对象
          • 基本使用
            • 读取文件
              • 封装ajax
                • 原生ajax请求
                • promise封装ajax
              • Promise.prototype.then()
                • 读取多个文件
                • Set
                • MAP
                • class
                • 利用async和await结合发送ajax请求
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档