Symbol、promise、生成器和迭代器

Symbol

ES6引入了一种新的原始数据类型symbol,表示独一无二的值,它是JS的第七种数据类型,是一种类似于字符串的数据类型。

symbol特点:

  1. symbol的值是唯一的,用来解决命名冲突的问题
  2. symbol值不能与其他数据进行运算
  3. symbol定义的对象属性不能使用for… in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

七种数据类型

//USONB     you are so niubility
            //u  undefined
            //s  String Symbol
            //o  object 
            //n  null number
            //b  boolean 

symbol对象的创建

    //创建symbol  第一种
        let s=Symbol();
        console.log(s,typeof s);
        let s2=Symbol('尚硅谷');
        let s3=Symbol('尚硅谷');
        console.log(s2==s3);
        //Symbol.for创建  第二种
        let s4=Symbol.for('尚硅谷')
        let s5=Symbol.for('尚硅谷')
        console.log(s4,typeof s4);
        console.log(s4==s5);
            //不能与其他数据类型进行运算
            // let result =s+100
            // let result =s>100;
            // let result =s+"100"
            //全都会报错

symbol创建对象属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //向对象中添加方法 up down 
         let game={
          
         }
         //声明一个对象
         let methods={
            up:Symbol(),
            down:Symbol()
         };
         game[methods.up]=function(){
            console.log('我可以改变形状');
         }
         game[methods.down]=function(){
            console.log('我可以快速下降');
         }
         console.log(game);
    </script>
</body>
</html>

symbol的内置属性

除了定义自己使用的symbol值以外,ES6还提供了11个内置的symbol值,指向语言内部使用的方法。

(47条消息) es6 Symbol 的内置属性_ixygj197875的博客-CSDN博客

Symbol.hasInstance 可以自己去控制类型检测(当其他对象使用instanceof 运算符,判断是否为该对象实例时,会调用该方法)
Symbol.isConcatSpreadable concat是用来合并数组,Symbol.isConcatSpreadable是用来控制数组是否可以展开
Symbol.unscopables 该对象指定了使用with关键字时,那些属性会被with环境排除
Symbol.match 字符串方法,自动的,不需要手动执行
Symbol.replace 字符串方法,自动的,不需要手动执行
Symbol.search 字符串方法,自动的,不需要手动执行
Symbol.split 字符串方法,自动的,不需要手动执行
Symbol.iterator 对象进行for…of循环时,会调用Symbol.iterator方法,返回该对象对应的而原始数据类型
Symbol.toPrimitive 该对象被转化为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
Symbol.toStringTag 在该对象上面调用toString方法时,返回该方法的返回值
Symbol.species 创建衍生对象时,会使用该属性
<script>
        // class Person{
        //     static [Symbol.hasInstance](param){
        //         console.log(param);
        //         console.log("我被用来检测类型了");
        //         return true;//这里返回什么,最后就会显示什么
        //     }
        // }
        // let o={}
        // console.log(o instanceof Person);

        const arr=[1,2,3];
        const arr2=[4,5,6];
        arr2[Symbol.isConcatSpreadable]=true;//等于true,控制数组内的值可以展开
        arr[Symbol.isConcatSpreadable]=false;//等于false,控制数组内的值不可以展开
        console.log(arr.concat(arr2));//将数组进行合并
    </script>

13-迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作。

1.ES6创造了一种新的遍历命令for…of循环,Iterator接口主要提供for…of消费

2.原生具备Iterator接口的数据(可用于for of遍历)

  • Array
  • Arguments
  • Set
  • Map
  • String
  • TypedArray
  • NodeList

3.工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  3. 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  4. 每调用一次next方法返回一个包含value和done属性的对象

注:需要自定义遍历数据的时候,要想到迭代器

    <script>
        //声明一个数组
        const  xiyou =['唐僧','孙悟空','猪八戒','沙和尚']
        // //使用for of遍历数组  遍历出来的是键值
        // for(let v of xiyou){
        //     console.log(v);
        // }
        // //使用for in遍历数组  遍历出来的是键名
        // for(let v in xiyou){
        //     console.log(v);
        // }
        // console.log(xiyou);
        let iterator =i=xiyou[Symbol.iterator]();
        //调用对象的next方法
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
    </script>

自定义遍历数据实例

    <script>
        //声明一个对象
        const banji = {
            name: '终级一组',
            stus: [
                '小明',
                '小红',
                '小宁',
                '小迪',
            ],
            [Symbol.iterator](){
                //索引变量
                let index=0;
                let _this=this;//让return里的this指向stus,也可以使用箭头函数实现
                return {
                    next :function(){
                        if(index<_this.stus.length){
                            const result={value:_this.stus[index],done:false};
                            //下标自增
                            index++;
                            //返回结果
                            return result;
                        }else{
                            return {value:undefined,done:true}
                        }
                    }
                };
            }
        }
        //遍历这个对象
        for (let v of banji) {
            console.log(v);
        }   //返回错误banji is not iterable

        // banji.stus.forEach(
        //     function (value, index, obj) {
        //         console.log("value = " + value);
        //     }
        // )//可以遍历,但不符合面向对象的思想

    </script>

生成器

生成器函数时ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同

  <script>
        //生成器其实就是一个特殊的函数  异步编程的一种新的解决方案
        //异步编程  之前用的是纯回调函数  node fs  ajax  mongodb(数据库)
        //函数代码的分隔符
        function* gen(){
            // console.log(111);
            yield '一只没有耳朵'
            // console.log(222);
            yield '一只没有尾巴'
            // console.log(333);
            yield '真奇怪'
            // console.log(444);
        }
        let iterator=gen();
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        //遍历
        for(let v of gen()){
            console.log(v);
        }
    </script>

生成器函数参数

   <script>
        function * gen(arg){
            console.log(arg);
            let one=yield 111;
            console.log(one);
            let two=yield 222;
            console.log(two);
            let three=yield 333;
            console.log(three);
        }
        //执行获取迭代器对象
        let iterator=gen('AAA');//整体传参
        console.log(iterator.next());
        //next 方法可以传入实参  返回的是上一个yield的返回值
        console.log(iterator.next('BBB'));
        console.log(iterator.next('CCC'));
        console.log(iterator.next('DDD'));
    </script>

生成器函数实例

实例1

    <script>
        //异步编程  文件操作  网络操作(ajax,request) 数据库操作
        //1s 后控制台输出111    2s 后控制台输出222    3s 后控制台输出333

        //回调地狱(之前的做法)
        // setTimeout(() => {
        //     console.log(111);
        //     setTimeout(() => {
        //         console.log(222);
        //         setTimeout(() => {
        //             console.log(333);
        //         }, 3000)
        //     }, 2000)
        // }, 1000)

        //利用生成器函数
        function one() {
            setTimeout(() => {
                console.log(111);
                iterator.next();
            }, 1000)
        }
        function two() {
            setTimeout(() => {
                console.log(222);
                iterator.next();
            }, 2000)
        }
        function three() {
            setTimeout(() => {
                console.log(333);
                iterator.next();
            }, 3000)
        }
        function* gen() {
            yield one();
            yield two();
            yield three();
        }
        //调用生成器函数
        let iterator = gen();
        iterator.next();
    </script>

实例2

   <script>
        //模拟获取  用户数据  订单数据  商品数据
        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();
            console.log(users);
            let orders=yield getOrders();
            console.log(orders);
            let goods=yield getGoods();
            console.log(goods);
        }
        //调用生成器函数
        let iterator=gen();
        iterator.next();

        // //这样做不符合实际的场景  数据是关联的,有了用户,才会有订单,才会有商品
        // getUsers();
        // getOrders();
        // getGoods();
    </script>

promise

Promise 的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

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

Promise对象有以下两个特点。

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

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

注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。

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

Promise也有一些缺点。

首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。

其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

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

基本用法

<script>
        //实例化Promise对象
        const p = new Promise(function (resolve, reject) {
      
      
            setTimeout(function () {
      
      
                let data = '数据库中的用户数据'
                //resolve
                // resolve(data);

                let err = "数据请求失败"
                reject(err);
            }, 1000);
        });

        //调用Promise对象的then方法
        p.then(function (value) {
      
      
            console.log(value);
        }, function (reason) {
      
      
            console.error(reason);
        })
    </script>

promise读取文件

//1.引入fs模块
const fs =require('fs');

//2.调用方法,读取文件(原始方法)
fs.readFile('./promise读取文件/小记.md',(err,data)=>{
    
    
//如果失败,则抛出错误
if(err) throw err;
//如果没有出错,则输出内容
console.log(data.toString());
});
//使用promise封装
const p=new Promisse(function(resolve,reject){
    
    
    fs.readFile("./promise读取文件/小记.md",(err,data)=>{
    
    
        //判断如果失败
        if(err) reject(err);
        //如果成功
        resolve(data);
    });
});
p.then(function(value){
    
    
    console.log(value);
},function(reason){
    
    
console.error(reason);
});

promise封装ajax

   <script>
        const p=new Promise((resolve,reject)=>{
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化
        xhr.open("GET", "https://api.apiopen.top/getJoke");
        //3.发送
        xhr.send();
        //4.绑定事件,处理响应结果
        xhr.onreadystatechange = function () {
            //判断
            if (xhr.readyState === 4) {
                //判断响应状态码   200-299表示成功
                if (xhr.status >= 200 && xhr.status < 300) {
                    //表示成功
                    resolve(xhr.response);
                } else {
                    reject(xhr.status);
                }
            }
        }
    })
    //指定回调
    p.then(function(value){
        console.log(value);
    },function(reason){
        console.error(reason);
    })
    </script>

promise-then方法

    <script>
        //创建promise对象
        const p=new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve("用户数据");
                // reject('出错啦');
            },1000)
        });
        //调用then方法   then方法的返回结果是promise对象,对象状态由回调函数的执行结果决定
        //1.如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值
        // const result=p.then(value=>{
        //     console.log(value);
            // //1.非promise类型的属性
            // return 'iloveyou';   //函数中如果不写return默认返回值是undefined
            // //2.是promise对象   
            // return new Promise((resolve,reject)=>{
            //     resolve('OK');   //这里成功就成功,这里失败就失败
            //     // reject('error');
            // });
            //3.抛出错误
            // throw new Error('出错啦!');
        //     throw '出错啦';
        // },reason=>{
        //     console.warn(reason);
        // })

            //then 可以链式调用,解决了回调地狱
            p.then(value=>{

            },reason=>{}).then(value=>{

            })
        // console.log(result);
    </script>

promise-catch方法

  <script>
        const p=new Promise((resolve,reject)=>{
      
      
            setTimeout(() => {
      
      
                //设置p对象的状态为失败,并设置失败的值
                reject("出错啦");
            }, 1000);
        });
        // p.then(function(value){},function(reason){
      
      
        //     console.error(reason);
        // });
        //换成catch方法
        p.catch(function(reason){
      
      
            console.warn(reason);
        })
    </script>

Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set本身是一个构造函数,用来生成 Set 数据结构

声明一个set

    <script>
        //声明一个set
        let s=new Set();
        let s2=new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);//会自动去重
        console.log(s2);
        //元素个数
        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);
        }
    </script>

Map

类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以做键。Map也实现了iterator接口,所以可以使用 扩展运算符 和**for…of…**进行遍历。

  <script>
        //声明Map
        let m=new Map()
        //添加元素
        m.set('name','尚硅谷');
        m.set('change',function(){
      
      
            console.log('我们可以改变你!');
        });
        let key={
      
      
            school:"河南科技学院"
        };
        m.set(key,['北京','上海','南阳']) 
        //第三种也可以写成这样
        // m.set({
      
      
        //     school:"河南科技学院"
        // },['北京','上海','南阳']) 
        //测量长度 size
        console.log(m.size);
        // 删除
        m.delete('name');
        //获取
        console.log(m.get('change'));
        console.log(m.get(key));
        //清空
        // m.clear()
        // console.log(m);
        //遍历
        for(let v of m){
      
      
            console.log(v);
        }
    </script>

模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小的文件组合起来。

模块化的好处

  1. 防止命名冲突
  2. 代码复用
  3. 高维护性

模块化规范产品

ES6 之前的莫滑块规范有:

  1. CommonJS => NodeJS、Browserify
  2. AMD => requireJS
  3. CMD => seaJS

ES6模块化语法

模块功能主要由两个命令构成:export和import

  • export命令用于规定模块的对外接口
  • import命令用于输入其他模块提供的功能

分别暴露,统一暴露,默认暴露

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script type="module">
        // //1.通用的导入方式
        // //引入m1.js 模块内容
        // import *as m1 from "./m1.js"
        // console.log(m1);
        // //引入m2.js 模块内容
        // import *as m2 from "./m2.js"
        // console.log(m2);
        // //引入m3.js 模块内容
        // import *as m3 from "./m3.js"
        // console.log(m3);
        // m3.default.change();

        // //2.解构赋值的形式
        // import{school,teach} from "./m1.js";
        // import{school as guigu,findjob} from "./m2.js";//Uncaught SyntaxError: Identifier 'school' has already been declared
        // //采用别名的形式
        // import{default as m3} from "./m3.js";
        // console.log(school); 
        // console.log(guigu); 
        // console.log(teach); 
        // console.log(m3); 

        //3.简便形式 针对默认暴露
        import m3 from "./m3.js";
        console.log(m3);
    </script>
</body>

</html>
//m1.js
//分别暴露
export let school ='尚硅谷';
export function teach(){
    console.log('我们可以教给你开发技能');
}
//m2.js
//统一暴露
let school="尚硅谷";
function findjob(){
    console.log("我们可以帮助你找工作!!");
}
//
export{
    school,findjob
}
//m3.js
//默认暴露
export default{
    school:"ATGUIGU",
    change: function(){
        console.log("我们可以改变你!!");
    }
}

ES新特性

ES7

 <script>
        //include
        const mingzhu=['西游记','三国演义','红楼梦','水浒传'];
        //判断
        console.log(mingzhu.includes('西游记'));
        console.log(mingzhu.includes('金瓶梅'));
        //幂运算
        console.log(2**10);
        console.log(Math.pow(2,10));
    </script>

ES8

async函数

  • async函数的返回值是promise对象
  • promise对象的结果由async函数执行的返回值决定
   <script>
        async function fn() {
            //返回一个字符串
            // return '尚硅谷';
            //返回的结果不是一个promise类型的对象,返回的结果就是成功的promise
            // return ;
            //抛出错误,返回结果是一个失败的promise
            // throw new Error('出错啦!')
            //返回的结果是一个promise
            return new Promise((resolve, reject) => {
                // resolve('成功的数据');
                reject('失败的错误');
            });
        }
        const result = fn();
        //调用then方法
        result.then(value => {
            console.log(value);
        }, reason => {
            console.warn(reason);
        })
        console.log(result);
    </script>

await表达式

  1. await必须写在async函数中
  2. await右侧的表达式一般为promise对象
  3. await返回的是promise成功的值
  4. await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
<script>
        //创建一个promise对象
        const p = new Promise((resolve, reject) => {
            // resolve('用户数据');
            reject('失败啦');
        })
        //await必须要放在async里面,但是async中可以没有await
        async function main() {
         try{
            let result= await p;
           console.log(result);
         }catch(e){
            console.log(e);
         }
        }
        main();
    </script>

对象方法扩展

    <script>
        //声明对象
        const school ={
            name:'尚硅谷',
            cities:['北京','上海',"南阳"],
            xueke:['前端','Java','大数据','运维']
        };
    //     //获取对象所有的键
    //     console.log(Object.keys(school));
    //     //获取对象所有的值
    //     console.log(Object.values(school));
    //     //entries 获取的是一个数组,键和值
    //     console.log(Object.entries(school));
    //     //创建Map
    //     const m=new Map(Object.entries(school));
    //     console.log(m);
    //     console.log(m.get('cities'));
            //返回对象属性的描述对象
            // console.log(Object.getOwnPropertyDescriptors(school));
            const obj=Object.create(null,{
                name:{
                    //设置值
                    value:'尚硅谷',
                    //属性特性
                    writable:true,//是否可写
                    configurable:true,//是否可以删除
                    enumerable:true,//是否可以枚举
                }
            });//应用:获取完这个对象之后,进行深层次的克隆
    </script>

猜你喜欢

转载自blog.csdn.net/L19541216/article/details/130303708