rest参数,symbol数据类型、set集合、map集合、iterator接口、generator生成器、promise

1. rest参数

​ rest参数是我们在ES6中新增的语法格式 它可以解析任何数据类型 比如说数组 对象 以及我们后面学的集合

​ 在我们使用rest参数的时候 我们需要在前面加上… 虽然知识点的名字叫做rest 但是名字我们自定义

​ 我们使用rest解开数组或者对象

let arr = [11,22,33,55,99];

console.log(arr);
// 使用...arr   将这三个点放在数组的前面   等于把数组中的元素取出
console.log(...arr);

// 如果说取出对象  直接取出的时候  会产生报错
let obj = {
    name : 'Eric',
    age : 18
};

// console.log(...obj);

// 可以使用...拷贝一个对象   那么是可以取出的
let newObj = {
    ...obj
};

console.log(newObj);

// 数组去重
let arr1 = [1,7,3,0,1,0,7,9,2,0,1];
let set = new Set(arr1);
let newArr1 = [...set];
console.log(newArr1);

​ 当然 rest也可以作为剩余参数使用 也就是我们所说的传递不定参数 和arguments类似

​ 因为在我们ES6中 我们大多数时候使用的是箭头函数 但是箭头函数不能使用arguments

​ 如果说 我们需要传递不定参数 那么我们是无法使用的

​ 那么这会 我们可以使用剩余参数

​ 剩余参数 使用的时候 需要在形参列表中有所体现 参数的名字自定义 但是参数前面要加上…

// 求和函数  一般情况下是N个加数

// let sum = (...value)=>{
//     // console.log(value);
//     let total = 0;
//     value.forEach(element=>total += element);
//     console.log(total);
// }
// sum(1,2,3,4,5,7);

// 传递普通参数
let sum = (a,c,...value)=>{
    console.log(value);
    let total = 0;
    value.forEach(element=>total += element);
    console.log(total);
}
sum(1,2,3,4,5,6,7);

// 错误的写法   如果说传递普通参数  那么剩余参数一定要在最后
// let sum = (...value,a,c)=>{
//     console.log(value);
//     let total = 0;
//     value.forEach(element=>total += element);
//     console.log(total);
// }
// sum(1,2,3,4,5,6,7);

rest参数和arguments参数的区别

1.arguments不能在箭头函数中使用 但是rest可以在箭头函数中使用

2.arguments传参的时候 我们不能在形参列表中传递参数 但是rest传参 我们必须在形参列表中使用 并且是…参数名

3.rest参数可以和常规参数一起进行传递 arguments不能 但是 如果说传递常规参数 那么rest参数必须放在最后

2. Symbol数据类型

定义

​ Symbol他是ES6新增的一种数据类型 它主要的作用是保证数据的唯一性

​ 比如说对象属性的名字或者方法的名字 可能会出现一些冲突 那么我们可以使用Symbol进行解决

​ 同时定义的两个Symbol 他们绝对不会相等

​ 他不是对象 也不是函数 只是一种数据类型 但是使用的时候 还是需要调用

// 使用Symbol
let sym1 = Symbol();

// console.log(sym1);
// console.log(typeof sym1);
// console.log(sym1 == sym1);  // true

let sym2 = Symbol();
// 两个Symbol绝对不相等
console.log(sym1 == sym2);  // false

​ 但是 我们在使用的时候 基本上使用的比较麻烦 因为我们无法确定Symbol()是什么 如果说这个Symbol作为对象的键

​ 我们都无法确认对象的键具体的代表是什么

​ 这中情况下 我们可以向Symbol内部传递一个参数 参数作为Symbol的标识

​ 但是注意 即使传递的参数相同 那么两个Symbol还是不会相等

let name = Symbol('姓名');
let user = Symbol('姓名');
let age = Symbol('年龄');

console.log(name);
console.log(age);
console.log(user);
console.log(user == name);  // false

​ 注意 Symbol数据类型不能和其他任何数据类型进行运算

console.log(age + "abc");
console.log(age + 123);
console.log(age + 12.3);
console.log(age + true);
console.log(age + undefined);
console.log(age + null);
使用

​ 有三种方式可以使用

​ 1.直接在对象中使用

​ 2.可以追加对象属性

​ 3.使用defineProperty方法进行添加属性

<script>
let name = Symbol('姓名');
let age = Symbol('年龄');
let sex = Symbol('性别');
let school = Symbol('学校');
let like = Symbol('爱好');
let address = Symbol('地址');
let birth = Symbol('生日');

// 第一种方式  直接添加
let obj = {
    [name] : 'Eric',
    [age] : 18,
    [sex] : '男',
    [school] : '吉林大学',
    [like] : ['吃','喝','旅游','女','学习','开车']
}
console.log(obj);
console.log(obj[age]);
console.log(obj[birth]);

// 第二种方式   向对象中追加属性
obj[address] = '吉林长春';

// 第三种方式  使用defineProperty方法进行追加属性
// 内置三个参数  第一个参数是原对象
// 第二个参数是Symbol
// 第三个参数是描述  描述还是一个对象  描述中有一个属性  属性是名value  值是新增属性值
Object.defineProperty(obj,birth,{
    value : '2002-07-18'
})

console.log(obj);
</script>

3. set集合

​ set是ES6中新增的数据结构 他是一个无序的 不重复的集合 结构类似于数组

​ 他是主要用来存储一些不重复的数据 或者作为数组去重使用

​ 使用set集合必须先进行实例化 new 可以内置一个参数 也可以不传参数 参数是一个数组

​ 内置方法

​ add : 添加一个集合元素

​ size属性 : 查看集合元素的数量 和数组的length一致

​ delete : 删除一个集合元素

​ has : 查看元素是否存在在这个集合中

​ clear : 清空集合

<script>
let arr = [1,7,3,0,1,0,7,9,2,0,1];

// 实例化一个set集合
let set = new Set(arr);
// let set1 = new Set();
console.log(set);
// console.log(set1);

// add  :  添加一个集合元素
set.add(99);
console.log(set);

// delete  :  删除一个元素
set.delete(99);
console.log(set);

// has  :  查看一个元素是否存在在集合中
console.log(set.has(1));
console.log(set.has(5));
console.log(set.has(9));
console.log(set.has(99));

// size属性  :  查看集合中的元素的数量
console.log(set.size);

// clear  :  清空集合
set.clear();
console.log(set);
</script>

数组的去重

<script>
let arr = [1,7,3,0,1,0,7,9,2,0,1];

// 首先去重数组  先定义一个set集合  将数组中的元素放到set集合中
// set集合会自动将数组的元素进行去重
let set = new Set(arr);
// console.log(set);

// 然后将set中的元素都取出来
// 注意  set不能使用for循环  或者是for...in进行遍历   需要使用for...of
// 但是我们可以使用剩余参数   解开集合   存储到新的数组中
let newArr = [...set];

console.log(newArr);
</script>

4. map集合

​ map也是ES6中新增的数据结构 也是一个无序的 不重复的集合 但是和set不同的是 set结构类似与数组

​ map的结构类似于对象 每一个元素是由键值对组成的

​ 在使用的时候 也是和set一样 需要实例化 new Map 内置一个参数

​ 参数是可选参数 如果说传递参数 那么参数是一个二维数组 每一个子数组内置两个元素 分别作为键值

​ 内置方法

​ set : 添加一个map元素 内置两个参数 第一个参数是键 第二个参数是值

​ delete : 删除一个map元素

​ size属性 : 查看map中的元素数量

​ has : 查看元素是否存在map集合中

​ get : 获取一个map元素

​ clear : 清空map集合

<script>
let arr = [
    ['name','Eric'],
    ['age',18],
    ['sex','男'],
    ['address','吉林长春']
];

// 创建一个map  实例化
let map = new Map(arr);
console.log(map);

// set添加一个元素
map.set('birth','2002-7-18');
console.log(map);

// delete删除一个元素
map.delete('birth');
console.log(map);

// size 查看元素的具体数量
console.log(map.size);

// has  查看元素是否存在在map集合中
console.log(map.has('birth'));
console.log(map.has('name'));

// get  获取一个map集合元素
console.log(map.get('name'));
console.log(map.get('age'));
console.log(map.get('birth'));

// clear  清空集合
map.clear();
console.log(map);
</script>

5. iterator迭代器

简介 : iterator 是一种接口机制 为不同的数据结构提供统一的访问机制

作用

​ 为不同的数据结构提供统一的访问机制

​ 使数据结构成员能够按照某种次序排序 一一迭代出来

​ ES6提供了一个新的遍历办法 for of

 Iterator主要是提供for of使用

原理

​ 创造一个指针 指向数据结构的起始位置

​ 第一次调用next() 指针自动指向数据结构的第一个成员

​ 接下来不断的调用next() 指针一直往后移动 直到指向最后一个成员

​ 每次调用next的时候 返回的值包括一个value done

​ 如果说 指向数据 返回为真 {value : ‘值’, done : false}

​ 如果说 指向最后了 没有值了 那么返回 {value : undefined , done : true}

​ 原生具备iterator接口的数据(可以用for of遍历)

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];

/*
    使用iterator接口机制迭代这个数组
        首先  我们创建数组指针  指向数组的起始位置
        每一次使用next方法进行调用  迭代数据
        每一次next之后  那么数组指针下移   指向下一个元素
        如果元素存在  有值  返回对象   {value  : '值',  done  :  false}
        如果说指针移动到最后   那么没有值了  返回对象  {value  :  undefined , done : true}

    首先  我们自定义一个函数  封装一个函数   主要是迭代数组使用

*/

function myIterator(object){
    // 创建数组指针   指向数组中的第0个元素的位置  起始位置
    let index = 0;
    return {
        next : function(){
            if (object.length > index){
                return {value:object[index++],done:false};
            }else{
                return {value:undefined,done:true};
            }
        }
    }
}

let iter = myIterator(arr);
console.log(iter.next());  //{value  : '贾思勰',  done  :  false}
console.log(iter.next());  //{value  : '左丘明',  done  :  false}
console.log(iter.next());  //{value  : '司马光',  done  :  false}
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

let str = 'abcd';
let striter = myIterator(str);
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
</script>

​ iterator迭代的数据结构

​ 其实在iterator中 我们是存在语法糖的 使用字符串 数组 set集合 map集合 中的Symbol.iterator 方法进行迭代

​ 注意 iterator不能迭代对象 iterator的语法糖也不能迭代对象

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];
// 使用iterator迭代数组
// 首先调用[Symbol.iterator]方法
let arrIter = arr[Symbol.iterator]();
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代字符串
let str = 'abc';
let strIter = str[Symbol.iterator]();
console.log(strIter.next());
console.log(strIter.next());
console.log(strIter.next());
console.log(strIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代set集合
let set = new Set(arr);
let setIter = set[Symbol.iterator]();
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代map集合
let map = new Map([['name','Eric'],['age',18]]);
let mapIter = map[Symbol.iterator]();
console.log(mapIter.next());
console.log(mapIter.next());
console.log(mapIter.next());


// 不能使用iterator迭代对象
let obj = {
    name : 'Mary',
    age : 13
};

let objIter = obj[Symbol.iterator]();
</script>

​ iterator的语法糖其实是for…of语句

​ for…of 可以迭代任何可迭代的数据类型 但是就是不能迭代对象

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];
// 使用for  of迭代数组
// for(let value of arr){
//     console.log(value);
// }

let str = 'abc';
// 使用for...of迭代字符串
// for(let value of str){
//     console.log(value);
// }

let set = new Set(arr);
// 使用for...of迭代set集合
// for(let value of set){
//     console.log(value);
// }

let map = new Map([['name','Eric'],['age',18]]);
// 使用for...of迭代map集合
for(let value of map){
    console.log(value);
}


// 报错  : 所有的数据解构使用for...of  都可以迭代  但是  for...of不能迭代对象
// let obj = {
//     name : 'Mary',
//     age : 13
// };
// for(let value of obj){
//     console.log(value);
// }
</script>

使用iterator迭代对象

<script>
let obj = {
    name : 'Eric',
    age : 18,
    sex : '男'
};

// iterator迭代对象
obj[Symbol.iterator] = function(){
    // 定义数组指针
    let index = 0;
    // 将对象中所有的键取出来组成一个数组
    let keys = Object.keys(this);
    return {
        next : ()=>{
            // 判断数组中的长度是否大于数组指针
            if (keys.length > index){
                return {value : this[keys[index++]],done : false}
            }else{
                return {value : undefined,done : true}
            }
        }
    }
}

let iter = obj[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
</script>

for…of和for…in和foreach之间的区别

for…of是iterator的语法糖 他能够遍历出iterator所有可迭代的数据类型和数据解构 set map 字符串 数组 不能迭代对象

foreach 只是遍历数组使用 不能用作其他 也不能迭代对象

for…in 是唯一一个可以迭代对象的一种语法结构 当然 也可以迭代数组 字符串

6. generator生成器

简介

​ ES6提供的解决异步编程的方案之一

​ Generator函数是一个状态机, 可控制函数执行过程

​ 可暂停函数(惰性求值), 内部yield可暂停,外部调用next方法可启动

​ 每次返回的是yield后的表达式结果

使用

​ 定义generator需要在function后面加上*

​ 调用函数不会打印任何函数数据,而是会返回一个指针对象

​ 调用指针对象中的next方法,来执行generator函数中的内容

​ 返回结果和iterator相似

使用

<script>
// generator函数  function后面需要加上一个*  证明是generator
function* myGenerator(){
    yield "这是第一次";
    yield "这是第二次";
    yield "这是第三次";
    yield "这是第四次";
    yield "这是第五次";
    return 'GAMEOVER';
}

let go = myGenerator();
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());


</script>

小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            padding: 0px;
            margin: 0px;
        }
        #app{
            width: 1200px;
            margin: 0 auto;
            /* border: 1px solid; */
        }
        #app div{
            width: 1200px;
            height: 44px;
            line-height: 44px;
            text-align: center;
            font-size: 20px;
            font-weight: 800;
            margin: 5px 0px;
            border: 1px solid;
        }
        #btn{
            width: 800px;
            height: 35px;
            font-size: 18px;
            display: block;
            margin: 20px auto;
            border: none;
            outline: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <div>显示1——20条数据</div>
    </div>
    <button id="btn">点击加载更多</button>
</body>
</html>
<script>
function* getData(){
    yield "显示21——40条数据";
    yield "显示41——60条数据";
    yield "显示61——80条数据";
    yield "显示81——100条数据";
    yield "显示101——120条数据";
    yield "显示121——140条数据";
    yield "显示141——160条数据";
    yield "显示161——180条数据";
    yield "显示181——200条数据";
    yield "显示201——220条数据";
}

let go = getData();

btn.onclick = function(){
    let div = document.createElement('div');
    let content = go.next().value;
    if (content == undefined){
        btn.style.display = 'none';
    }else{
        div.innerHTML = content;
        app.appendChild(div);
    }
}

</script>

7. promise

概念

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

​ ES6的Promise是一个构造函数, 用来生成Promise实例, Promise实例是异步操作管理者

​ Promise代表了未来某个将要发生的事件(通常是一个异步操作) 有了Promise对象

​ 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(回调地狱)

​ Promise本身还是在使用回调函数(只不过比回调函数多了一种状态管理)

使用

​ 创建promise对象,实例化Promise

​ 参数是回调函数,内置两个参数,resolve和reject

​ promise三个状态

​ 初始化状态 pending

​ 成功状态 fullfilled

​ 失败状态 rejected

调用

​ then : 触发resolve方法执行then

​ catch : 触发reject方法执行catch

<script>
/*
    编辑一个Promise
    Promise是一个构造函数   需要实例化才能使用  首先实例化Promise
    内置一个参数  参数是回调函数
        回调内置两个参数
            第一个参数是成功状态  它本身是一个函数
            第二个参数是失败状态  它本身也是一个函数
    promise有一个返回值  返回值是一个promise对象

    在promise内部  我们可以编辑三种状态
        1.初始化状态
        2.成功状态
        3.失败状态
*/

let promise = new Promise((resolve,reject)=>{
    // 定义一个初始值
    let num = 9;
    // 判定初始化状态
    if (num > 99){
        // 成功的话  我们可以调用成功状态   也就是resolve
        // resolve本身是一个函数
        // console.log(typeof resolve);
        resolve('牵手了  成功');
    }else{
        // 失败的话  我们可以调用失败状态  reject  他也是一个函数
        // console.log(typeof reject);
        reject('分手了');
    }
});

// 我们定义完的promise对象和没写一样  和定义的函数一样  没有调用
// 比如说成功状态的函数和是失败状态的函数也没有定义
// 如果说  我们触发promise   那么我们使用promise对象中的then方法进行触发
// then方法中内置一个或者两个参数  第一个参数是成功状态的函数
// 第二个参数是失败状态的函数  可选
promise.then((data)=>{
    console.log(data);
},(error)=>{
    console.log(error);
})
</script>
捕获异常

​ 在使用then的时候是无法捕获异常的

​ 但是在catch中可以捕获异常

​ try : 可能出现异常的代码

​ catch : 如果try出现错误,代码执行catch

​ finally : 不管会不会发生异常,都会执行finally中的代码

<script>
/*
    异常处理
    主要分为三个关键字  分别是try  catch   finally
    try  :  这个执行体中  存放着可能出错的代码
        如果内部代码没有报错行为  那么直接执行  但是如果说代码报错了  那么执行catch里面的代码
    catch  :  准备一些代码  如果说try中的代码出错  我们去处理try中的代码
    finally  :  无论代码报错与否  那么都执行  比较鸡肋
*/

let num = 100;

try{
    console.log(num);
    // console.log('代码没出错的时候执行的');
}catch{
    let num = 100;
    console.log(num);
    // console.log('try里面面有问题了  你想起我来了');
}finally{
    console.log('怎么做我都执行');
}
</script>
链式操作

​ then方法的第一个参数,成功时的回调函数,分两种情况:

​ 返回了一个普通的数据(非promise),这个值会作为参数传递给下一个then的成功回调

​ 返回了一个promise,下一个then的执行,取决于这个promise状态的改变

// 捕获异常  详见17.html
// 使我们讲解异常处理  主要是对peomise进行链式操作
// 链式操作
let promise = new Promise((resolve,reject)=>{
    let num = 9;
    if (num > 99){
        resolve('牵手了  成功');
    }else{
        reject('分手了');
    }
});

// 当我们触发promise的时候  使用then方法
// 但是then方法中  我们一般情况下  只传递一个参数  参数是成功状态
// 我们then方法的返回值还是一个promise
// console.log(promise);
// 我们失败状态一般使用catch来处理  这是异常处理
promise.then((data)=>{
    console.log(data);
}).catch((error)=>{
    console.log(error);
})
如何使用promise处理回调地狱
<script>
let promise = new Promise((resolve,reject)=>{
    resolve('京东的工艺');
})

// 我们使用promise对象then完之后  返回值依旧是promise
// 我们可以继续使用then进行触发
// 此时  新的返回值promise中的resolve状态(成功状态)就是刚刚的返回值
// 也就是说  我们触发时候的返回值  作为新的promise的成功状态   resolve状态
promise.then((data)=>{
    console.log(data);
    return data + '里面的打火机';
}).then(data=>{
    console.log(data);
    return data + "里面的zippo";
}).then(data=>{
    console.log(data);
    return data + "里面的黑色的";
}).then(data=>{
    console.log(data);
    return data + "青春靓丽";
}).then(data=>{
    console.log(data + "的打火机");
})
</script>
面试题

谈一谈你对promise的理解?

答案: Promise用来解决异步回调问题,由于js是单线程的,很多异步操作都是依靠回调方法实现的,这种做法在逻辑比较复杂的回调嵌套

中会相当复杂;也叫做回调地狱;promise用来将这种繁杂的做法简化,让程序更具备可读性,可维护性;promise内部有三种状态,

pedding,fulfilled,rejected;pedding表示程序正在执行但未得到结果,即异步操作没有执行完毕,fulfilled表示程序执行完毕,且执

行成功,rejected表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非是要报错。其实,promise和回调函数一样,都是要

解决数据的传递和消息发送问题,promise中的then一般对应成功后的数据处理,catch一般对应失败后的数据处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值