关于ES6新特性的总结

目录

  • 1.let & const
  • 2.解构赋值
  • 3.模板字符串
  • 4.简化对象写法
  • 5.箭头函数
  • 6.函数参数的默认值设置
  • 7.rest参数
  • 8.扩展运算符
  • 9.Symbol
    • Symbol特点
    • 创建Symbol
    • Symbol使用场景
    • Symbol内置值
  • 10.迭代器
  • 11.生成器
  • 12.Promise
    • 基本使用
    • Promise封装读取文件
    • Promise封装ajax
    • Promise.prototype.then方法
    • 通过链式调用实现按顺序读取文件
    • Promise对象catch方法
  • 13.set(集合)
    • 集合的属性和方法
    • set的应用
  • 14.Map

1.let & const

1) let,作用与var类似,用于声明变量
特性:

  1. let 不能重复声明变量,var 可以重复声明变量;
  2. 块级作用域,es5中存在全局作用域、函数作用域、eval作用域;es6中引入了块级作用域,let声明的变量在块级作用域{}内有效
  3. let声明的变量不存在var的变量提升问题

举个例子:



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="container">
        <h2 class="page-header">点击切换颜色</h2>
        <div class="item">1</div>
        <hr>
        <div class="item">2</div>
        <hr>
        <div class="item">3</div>
    </div>

    <script>
        // 获取div对象
        let items = document.getElementsByClassName('item')

        // 遍历并绑定事件 遍历时let i
        for(let i = 0; i < items.length; i++){
            items[i].onclick = function(){
                items[i].style.background = 'pink'
            }
        }
        /*
        相当于在3个块级作用域内分别声明了i
        {
            let i = 0
            items[i].onclick = function(){
                items[i].style.background = 'pink'
            }
        }
        {
            let i = 1
            items[i].onclick = function(){
                items[i].style.background = 'pink'
            }
        }
        {
            let i = 2
            items[i].onclick = function(){
                items[i].style.background = 'pink'
            }
        }
        */

        /*
        // 遍历并绑定事件 遍历时var i
        for(var i = 0; i < items.length; i++){
            items[i].onclick = function(){
                // 修改当前元素的背景颜色
                this.style.background = 'pink' // 此处this指向’被绑定的元素对象‘,即调用该函数的对象
                // 此处不能和上文一样使用 items[i].style.background = 'pink',
                // 因为var的i不考虑块级作用域, 则相当于在全局声明了一个变量,循环结束后i=3,
                // 函数执行时向上层寻找最终得到全局变量i=3,而items[3]为undefined
            }
        }
        相当于
        {
            var i = 0
            // ...

        }
        {
            var i = 1
            // ...
        }
        {
            var i = 2
            // ...
        }
        {
            var i = 3
        }

        */
    </script>
</body>

<style>
    .item{
        width: 200px;
        height: 50px;
        border-radius: 2%;
        background-color: brown;
    }
</style>

</html>

2) const 用于声明常量
注意事项:

  1. 一定要赋初始值
  2. 一般常量使用大写(属于编程规范)
  3. 常量值不能修改
  4. 存在块级作用域
  5. 对于数组和对象的元素修改,不算做对常量的修改,不会报错(因为引用数据类型保存的是内存地址,所以声明数组和对象时可以使用const声明,以此保证其保存的内存地址不变)

2.解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值

1) 数组的解构

const Web = ['html', 'css', 'javascript']
let [tool1, tool2, tool3] = Web

console.log('tool1-----', tool1) // html
console.log('tool2-----', tool2) // css
console.log('tool3-----', tool3) // javascript

2) 对象的解构

const liMing = {
    name: 'liMing',
    age: '22',
    tell: function(){
        console.log(`I am liMing`)
    }
}

let {name, age, tell} = liMing

console.log(name) // 'liMing'
console.log(age) // '22'
console.log(tell) // f(){...}
tell() // I am liMing

3.模板字符串

特性:

  1. (反引号)内容中可以直接出现换行符,’ '和" "中则不可以,出现会报错
  2. 可以直接进行变量拼接

4.简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法(在属性名和变量名相同的情况下),这样的书写更加简洁

let name = 'LiMing'
let tell = function(){
    console.log('I am LiMing')
}

const liMing = {
    name,
    tell,
    sayHi(){
        console.log('hello')
    }
}

// 等效于
// const liMing = {
//     name: name,
//     tell: tell,
//     sayHi: function(){
//         console.log('hello')
//     }
// }

console.log(liMing)
liMing.tell()
liMing.sayHi()

5.箭头函数

function声明的区别:

1.箭头函数this是静态的。

  • 箭头函数内的this指向上层对象;始终指向函数声明时所在作用域下的this的值,无法被call改变
  • 普通函数内的this指向调用其函数的对象
function getName(){
    console.log(this.name)
}

let getName2 = ()=>{
    console.log(this.name)
}

// 设置window对象的name属性
window.student = 'LiMing'
const student = {
    name: 'HanMei'
}

// 直接调用
getName() // LiMing
getName2() // LiMing

// call方法调用
getName.call(student) // HanMei
getName2.call(student) // LiMing

2.箭头函数不能作为构造函数实例化对象

let Person = (name, age)=>{
    this.name = name
    this.age = age
}
let me = new Person('LiMing', 20) // 报错:Uncaught TypeError: Person is not a constructor

3.箭头函数不能使用arguments变量,但是可以使用....rest

let fn = ()=>{
    console.log(arguments)
}

fn(1, 2, 3) // 报错:Uncaught ReferenceError: arguments is not defined


let fn2 = (...rest)=>{
    console.log(...rest)
}

fn2('a','b','c') // a b c

4.箭头函数的简写
① 当形参有且只有一个的时候,可以省略()
② 当代码体只有一条语句的时候,可以省略{},此时return必须省略,而且语句的执行结果就是函数的返回值

// 当形参有且只有一个的时候,可以省略`()`
let add = n => {
    return n + n
}

console.log(add(9))

// 当代码体只有一条语句的时候,可以省略`{}`,此时`return`必须省略,而且语句的执行结果就是函数的返回值
let pow = n => n*n

console.log(pow(9))

5.箭头函数的例子
箭头函数适合与this无关的回调,比如定时器setTimeout(()=>{...}, 2000)、数组的方法回调arr.filter((item)=>{...})
不适合与this有关的回调,比如dom元素的事件回调ad.addEventListener('click', function(){...}、对象内的方法定义{name: 'LiMing', getName: function(){this.name}}
例1:

// 需求-1 点击div 2s后颜色变红

// 获取元素
let ad = document.getElementById('ad')
// 绑定事件
ad.addEventListener('click', function(){
    setTimeout(function(){
        console.log(this) // 定时器里的this指向window
        this.style.background = 'brown' // 报错
    }, 2000)
})

//解决方案1
// ad.addEventListener('click', function(){
//     // 保存this的值
//     let _this = this // _this指向ad
//     setTimeout(function(){
//         console.log(_this) 
//         _this.style.background = 'brown'
//     }, 2000)
// })

// 解决方案2
// ad.addEventListener('click', function(){
//     setTimeout(()=>{
//         console.log(this) 
//         this.style.background = 'brown' // this指向函数声明时所在作用域下this的值 即ad
//     }, 2000)
// })

例2:

// 需求-2 从数组中返回偶数的元素
const arr = [1, 6, 9, 10, 100, 25]
const result = arr.filter(function(item){
    if(item %2 === 0){
        return true
    }else{
        return false
    }
})

// 可以用箭头函数
// const result = arr.filter(item => {
//     if(item % 2 === 0){
//         return true
//     }else{
//         return false
//     }
// })
// 还可以简写为
// const result = arr.filter(item => item % 2 === 0)

console.log(result)

6.函数参数的默认值设置

ES6允许给函数参数赋初始值

function add(a, b, c=10){ // 具有默认值的参数,一般位置要靠后
    return a + b + c
}
console.log(add(1,2,))

可以与解构赋值一起使用

function connect({host='127.0.0.1', port, username, password}){
    console.log(host, port)
    console.log(username, password)
}

connect({
    port: 3306,
    username: 'root',
    password: 'root',
})

7.rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments

// ES5获取实参的方式
function printStudent(){
    console.log(arguments) // arguments为一个对象
}
printStudent('LiMing','HanMeimei')

// ES6获取实参的方式
function printFriend(friend1, friend2, ...rest){ // rest参数必须放在形参列表最后,否则会报错
    console.log(friend1) 
    console.log(friend2) 
    console.log(rest) // 得到一个数组,可以使用数组api
}
printFriend('小猫','小狗','兔子','鸭子')
// 小猫
// 小狗
// ['兔子','鸭子']

8.扩展运算符

...能将「数组」转为逗号分隔的「参数序列」
注:虽然形式与rest参数类似,但是rest参数是用在函数定义时的形参位置,扩展运算符是用在函数实际调用时的实参位置

const STUDENTS = ['小明','小芳','小红']
function printStudent(){
    console.log(arguments)
}

printStudent(STUDENTS) // 参数为一个数组,数组内包含3个元素
printStudent(...STUDENTS) // 参数为3个元素

应用场景:

  1. 数组的合并
const STUDENTS1 = ['小明','小芳','小红']
const STUDENTS2 = ['小吴', '小王']

// es5写法
const STUDENTS_ES5 = STUDENTS1.concat(STUDENTS2)
// es6写法
const STUDENTS_ES6 = [...STUDENTS1, ...STUDENTS2]

console.log('es5------',STUDENTS_ES5)
console.log('es6------',STUDENTS_ES6)
  1. 数组的克隆
const STUDENTS1 = ['小明','小芳','小红']

const PUPIL = [...STUDENTS1] // 注意:如果数组内元素是引用类型,拷贝的是内存地址,为浅拷贝
console.log('PUPIL----',PUPIL)
  1. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div')
console.log(divs) // 此处得到的divs实际是一个对象

const divsArr = [...divs] // 将其转为真正的数组,从而可以使用数组的api譬如filter、map
console.log(divsArr)

9.Symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第7种数据类型,是一个类似字符串的数据类型

Symbol特点

  1. Symbol的值是唯一的,用来解决命名冲突的问题
  2. Symbol值不能与其他数据进行运算,也不能与自己进行运算,譬如+、-、*、/、比较运算
  3. Symbol定义的对象属性不能使用for…in遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

创建Symbol

  1. 通过let s2 = Symbol('张三') 的方式创建Symbol,'张三’作为Symbol描述,作用相当于注释,这种方式创建的Symbol,即使传入的描述一致,但实际返回的值是不同的
// 创建Symbol
let s = Symbol()
console.log(s,typeof s) // Symbol() "symbol"

let s2 = Symbol('张三') // '张三'作为Symbol描述,作用相当于注释
let s3 = Symbol('张三') // 即使传入的描述一致,但实际返回的值是不同的
console.log(s2 === s3) // false
  1. 通过Symbol.for()创建Symbol,这种方式创建Symbol,传入的描述一致,实际返回的值也一致,可以得到唯一的Symbol
// Symbol.for创建Symbol
let s4 = Symbol.for('张三')
let s5 = Symbol.for('张三')
console.log(s4 === s5) // true

Symbol使用场景

给对象添加属性和方法。由于Symbol值具有唯一性,所以可以很安全地把属性和方法加入对象中,如下所示

let game = {
    up: 'upp',
    down: 'doown'
}

let methods = {
    up: Symbol(),
    down: Symbol(),
}

// 添加方法
game[methods.up] = function(){
    console.log('up up up')
}
game[methods.down] = function(){
    console.log('down down down')
}

console.log('game----', game)
// 调用
game[methods.up]()
let youxi = {
    name: '狼人杀',
    [Symbol('say')]: function(){ // 此处不能直接写 Symbol('say'): function(){...},因为Symbol('say')是动态的,和上面固定的'name'不一样
        console.log('发言')
    }
}

Symbol内置值

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

  1. Symbol.hasInstance
    当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
 class Person{
        static [Symbol.hasInstance](param){
            console.log('param----', param)
            console.log('检测类型')
        }
    }

    let o = {}

    console.log(o instanceof Person)
    // param---- {}
    // 检测类型
    // false
  1. Symbol.isConcatSpreadable
    对象的Symbol.isConcatSpreadable属性等于一个bool值,表示该对象用于Array.prototype()时,是否可以展开
const arr1 = [1,2,3]
const arr2 = [4,5,6]
arr2[Symbol.isConcatSpreadable] = false // arr2不可展开
const arr = arr1.concat(arr2)
console.log(arr) // [1,2,3,[4,5,6]]
  1. Symbol.unscopables
    该对象指定了使用with关键字时,哪些属性会被with环境排除
  2. Symbol.match
    当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值
  3. Symbol.replace
    当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值
  4. Symbol.search
    当该对象被str.search(myObject)方法调用时,会返回该方法的返回值
  5. Symbol.split
    当该对象被str.split(myObject)方法调用时,会返回该方法的返回值
  6. Symbol.iterator
    对象进行for ... of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
  7. Symbol.toPrimitive
    该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
  8. Symbol.toStringTag
    在该对象上调用toString方法时,返回该方法的返回值
  9. Symbol.species
    创建衍生对象时,会使用该属性

10.迭代器

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

ES6创造了一种新的遍历命令for...of循环,iterator接口主要供for...of消费
注:for...of遍历的是键值,for...in遍历的是键名
for...of不能对属性值进行修改,forEach()可以

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

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

工作原理:

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  3. 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  4. 每调用next方法返回一个包含valuedone属性的对象,done属性表示遍历是否结束
const food = ['鱼香肉丝','糖醋里脊','酸菜鱼']
for(let item of food){
    console.log(item)
}

let iterator = food[Symbol.iterator]()

console.log(iterator.next()) // {value: "鱼香肉丝", done: false}
console.log(iterator.next()) // {value: "糖醋里脊", done: false}
console.log(iterator.next()) // {value: "酸菜鱼", done: false}
console.log(iterator.next()) // {value: undefined, done: true} true 表示遍历已经结束

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

迭代器应用-自定义遍历数据(即自己手动实现一个迭代器)

// 声明一个对象
const school = {
    name: '三中',
    students: [
        'LiMing',
        'HanMeimei',
        'WangFang',
    ],
    [Symbol.iterator](){
        // 声明一个索引变量
        let index = 0
        return {
            next: ()=>{
                if(index < this.students.length){
                // if(index < 3){
                    const result = {value: this.students[index], done: false}
                    // 下标自增
                    index++
                    // 返回结果
                    return result
                }else{
                    return {value: undefined, done: true}
                }
            }
        }
    }
}

// 遍历这个对象
for(let item of school){
    console.log(item)
}

11.生成器

生成器本身是一个特殊的函数,生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数不同

  • 执行生成器函数,返回的是一个迭代器对象,通过iterator.next()调用执行函数内语句
function * gen(){
    console.log('hello generator')
}
let iterator = gen() // 返回的是一个迭代器对象
// console.log(iterator)
// 通过.next()调用执行函数内语句
iterator.next() // hello generator
  • yield是函数代码的分隔符,结合调用iterator.next()方法,实现函数gen1的语句的分段执行
function * gen1(){
    console.log('--- 1 ---')
    yield '耳朵' // 函数代码的分隔符
    console.log('--- 2 ---')
    yield '尾巴'
    console.log('--- 3 ---')
}

let iterator1 = gen1()
iterator1.next() // --- 1 ---
iterator1.next() // --- 2 ---
iterator1.next() // --- 3 ---
// 通过调用.next()方法,实现函数gen1的语句的分段执行
  • 使用for...of遍历函数执行后返回的迭代器对象,每一次遍历的itemyield后的表达式或者自变量的值
function * gen1(){
    yield '耳朵' // 函数代码的分隔符
    yield '尾巴'
}

// 遍历,每一次遍历的item为yield后的表达式或者自变量的值
for(let item of gen1()){
    console.log(item)
}
// 执行结果:
// 耳朵
// 尾巴

// 注:next调用和for...of调用同时存在,只会支持最先的一个
  • 生成器函数的参数传递
function * gen(args){
    console.log(args) // 'aaa'
    let one = yield 111
    console.log(one) // 'bbb'

    let two = yield 222
    console.log(two) // 'ccc'
    
    let three = yield 333
    console.log(three)
}

// 执行生成器函数获取迭代器对象
let iterator = gen('aaa')

console.log(iterator.next()) // {value: 111, done: false}
// next方法可以传入实参,传入的实参会作为上一个yield后返回的结果
console.log(iterator.next('bbb')) // {value: 222, done: false}
console.log(iterator.next('ccc')) // {value: 333, done: false}
console.log(iterator.next('ddd')) // {value: undefined, done: true}
  • 生成器函数实例1:
    1s后控制台输出111 --> 2s后控制台输出222 --> 3s后控制台输出333 ==> 总计耗时6s
   // 异步编程,如文件操作、网络请求、数据库操作
    // 1s后控制台输出111 --> 2s后控制台输出222 --> 3s后控制台输出333  ==> 总计耗时6s

    // 用生成器函数实现
    function one (){
        setTimeout(()=>{
            console.log(111)
            iterator.next()
        }, 1000)
    }

    function two (){
        setTimeout(()=>{
            console.log(222)
            iterator.next()
        }, 2000)
    }

    function three (){
        setTimeout(()=>{
            console.log(333)
        }, 3000)
    }

    function * gen(){
        yield one()
        yield two()
        yield three()
    }

    let iterator = gen()
    iterator.next()
    

    // 以下为回调地域做法
    // setTimeout(()=>{
    //     console.log(111)
    //     setTimeout(()=>{
    //         console.log(222)
    //         setTimeout(()=>{
    //             console.log(333)
    //         }, 3000)
    //     }, 2000)
    // }, 1000)
  • 生成器函数实例2:
    模拟获取 用户数据 --> 订单数据 --> 商品数据
// 模拟获取 用户数据 --> 订单数据 --> 商品数据
function getUsers(){
    setTimeout(()=>{
        let data = '用户数据'
        iterator.next(data) // 相当于把得到的数据,传回users
    }, 1000)
}

function getOrders(){
    setTimeout(()=>{
        let data = '订单数据'
        iterator.next(data)
    }, 2000)
}

function getGoods(){
    setTimeout(()=>{
        let data = '商品数据'
        iterator.next(data)
    },3000)
}

// 定义生成器函数
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()

12.Promise

PromiseES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

  1. Promise构造函数:Promise(excutor){}
  2. Promise.prototype.then方法
  3. Promise.prototype.catch方法

基本使用

// 实例化Promise对象
const p = new Promise(function(resolve, reject){
    setTimeout(()=>{
        let data = '数据库中的用户数据'
        // resolve(data)
        let err = '数据读取失败'
        reject(err)
    },1000)
})

p.then((value)=>{
    console.log('enter success')
    console.log(value)
},err=>{
    console.log('enter failed')
    console.log(err)
})

Promise封装读取文件

// 1.引入fs模块 fileSystem 文件系统
const fs = require('fs')

// 2.调用方法读取文件
// fs.readFile('./resource/file.md', (err, data)=>{ // data是一个buffer,用来存储2进制文件,用法跟数组类似
//     // 如果失败,抛出错误
//     if(err) throw err
//     // 如果成功,读取文件
//     console.log(data.toString())
// })

// 3.使用promise封装
const p = new Promise(function(resolve, reject){
    fs.readFile('./resource/file.md', (err,data)=>{
        if(err){
            reject(err)
        }else{
            resolve(data.toString())
        }
    })
})
p.then((value)=>{
    console.log(value)
},(reason)=>{
    console.error(reason)
})

Promise封装ajax

// 接口地址:https://api.apiopen.top/getJoke
// 原生ajax发送请求
// // 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 ){
//         // 判断响应状态码
//         if(xhr.status >= 200 && xhr.status < 300){
//             // 如果状态码为成功,打印返回结果
//             console.log(xhr.response)
//         }else{
//             // 如果失败
//             console.error(xhr.status)
//         }
//     }
// }


// promise封装发送ajax请求
const p = new Promise((resolve, reject)=>{
    const xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://api.apiopen.top/getJoke')
    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((value)=>{
    console.log(value)
},(reason)=>{
    console.log(reason)
})

Promise.prototype.then方法

then方法的返回结果,依然是一个promise对象,其状态的成功或失败,由then里的回调函数的执行结果决定

  • 如果回调函数中返回的结果是非promise类型的属性,状态为成功,且return的结果就是该promise成功后resolve的值
    注: 如果没有return,则默认返回undefined,所以状态依然为成功
  • 如果返回的结果是promise对象,则该promise对象的状态就是then返回的promise对象的状态
  • 如果是抛出一个值(如一个错误),则状态为失败
const p = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('用户数据')
        // reject('出错啦')
    }, 1000)
})

const result = p.then((value)=>{ // p执行resolve后,状态为成功,执行第一个函数
    console.log(value )
    // 1.返回非promise对象的情况
    // return 233 // 233
    // 2.返回promise对象
    return new Promise((resolve, reject)=>{
        resolve('ok') // 状态为成功,值=ok
        // reject('error!!') // 状态为失败

    })
    // 3.抛出错误
    // throw new Error('error!!!')
},(reason)=>{ // p执行reject后,状态为失败,执行第二个函数
    console.warn(reason)
})

// then方法的返回结果,依然是一个promise对象,其状态的成功或失败,由then里的回调函数的执行结果决定
console.log(result)

then方法的这个特性,决定了then方法可以进行链式调用

const p = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('用户数据')
        // reject('出错啦')
    }, 1000)
})

// 链式调用
p.then((value)={
    // ...
}).then((value)=>{
    // ...
})

通过链式调用实现按顺序读取文件

// 1.引入fs模块 fileSystem 文件系统
const fs = require('fs')

// 使用传统方式实现 读取文件1 => 读取文件2 => 读取文件3
// fs.readFile('./resource/file1.md', (err, data)=>{
//     let data1 = data.toString()
//     fs.readFile('./resource/file2.md', (err,data)=>{
//         let data2 = data.toString()
//         fs.readFile('./resource/file3.md', (err,data)=>{
//             let data3 = data.toString()
//             let data_all = {data1,data2,data3}
//             console.log(data_all)
//         })
//     })
// })

// 使用promise方式实现 读取文件1 => 读取文件2 => 读取文件3
const p = new Promise((resolve, reject)=>{
    fs.readFile('./resource/file1.md', (err,data)=>{
        resolve(data)
    })
})

p.then((value) => {
    return new Promise((resolve, reject)=>{
        fs.readFile('./resource/file2.md',(err,data)=>{
            let data_all =  {
                data1: value.toString(),
                data2: data.toString()
            }
            resolve(data_all)
        })
    })
}).then((value)=>{
    return new Promise((resolve,reject)=>{
        fs.readFile('./resource/file3.md', (err,data)=>{
            value.data3 = data.toString()
            resolve(value)
        })
    })
}).then(value=>{
    console.log(value)
    //  { data1: '# 这是文件1', data2: '# 这是文件2', data3: '# 这是文件3' }
})

Promise对象catch方法

用于指定promise对象失败的回调

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        // 设置p对象的状态为失败
        reject('opps error')
    },1000)
})

// p.then((value)=>{}, (reason)=>{
//     console.error(reason)
// })

// 相当于then里面的第二个回调函数
p.catch((reason)=>{
    console.warn(reason)
})

13.set(集合)

ES6提供了新的数据结构set(集合),本质上是一个对象。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用「扩展运算符」和for...of进行遍历

集合的属性和方法

size,返回集合的元素个数
add,增加一个新元素,返回当前集合
delete,删除元素,返回Boolean
has,检测集合中是否包含某个元素,返回Boolean

let s = new Set(['风声','雨声','读书声','风声']) // 可以接受可迭代数据,一般传入数组
// '风声','雨声','读书声'

let size = s.size // 查看元素个数
let has = s.has('读书声') // 检测是否含该元素 true
s.add('水声') // 添加元素
s.delete('读书声') // 删除元素
let has2 = s.has('读书声') // 检测是否含该元素 false

// 遍历集合
for(let item of s){
    console.log(item)
}
s.clear() // 清空集合

console.log(s, has,has2, typeof s)

set的应用

数组去重

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
// 数组去重
let result = [...new Set(arr)]
console.log(result) // [1, 2, 3, 4, 5]

求交集

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let arr2 = [4, 5, 6, 5, 6]

// 求交集
let result = [...new Set(arr)].filter(item => { // 对arr去重并进行遍历
    let s2 = new Set(arr2) // 将arr2变为元素不重复的集合
    if(s2.has(item)){ // 如果元素存在s2中
        return true
    }else{
        return false
    }

})
console.log(result) // [4, 5]

// 简化写法
let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result2)

求并集

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let arr2 = [4, 5, 6, 5, 6]

// 求并集:连接两个数组 => 转为元素不重复的集合 => 转为数组
let union = [...new Set([...arr, ...arr2])]
console.log(union)
// [1, 2, 3, 4, 5, 6]

求差集

let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let arr2 = [4, 5, 6, 5, 6]

// 求差集-arr对arr2求差集,即求arr里面有但是arr2里没有的元素,相当于求交集的逆运算
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(diff) // [1, 2, 3]

14.Map

ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用「扩展运算符」和for...of进行遍历
Map的属性和方法:

size,返回Map的元素个数
set,增加一个新元素,返回当前Map
get,返回键名对象的键值
has,检测Map中是否包含某个元素,返回Boolean
clear,清空集合,返回undefined

// 声明Map
let m = new Map()

// 添加元素
m.set('name','LiMing') // 键名,键值
m.set('tell',function(){
    console.log('I am LiMing ')
})
let friend = {
    school: '三中'
}
m.set(friend,['小吴','小王','小芳'])

// 删除元素
m.delete('tell')

// 获取元素
let friends = m.get(friend)
console.log(friends)

// 获取元素个数
let size = m.size
console.log(size)

// 遍历Map
for(let item of m){
    console.log('item---',item)
    // 每一个item都是一个数组,第一个元素为键,第二个元素为值
}

// 清空Map
m.clear()
console.log(m)
console.log(typeof m)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/298.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

求职(怎么才算精通JAVA开发)

在找工作的的时候,有时候我们需要对自己的技术水平做一个评估。特别是Java工程师,我们该怎么去表达自己的能力和正确认识自己所处的技术水平呢。技术一般的人,一般都不敢说自己精通JAVA,因为你说了精通JAVA几乎就给了面试官一个可以随便往死里问的理由了。很多不自信的一般…

《ChatGPT是怎样炼成的》

ChatGPT 在全世界范围内风靡一时&#xff0c;我现在每天都会使用 ChatGPT 帮我回答几个问题&#xff0c;甚至有的时候在一天内我和它对话的时间比和正常人类对话还要多&#xff0c;因为它确实“法力无边&#xff0c;功能强大”。 ChatGPT 可以帮助我解读程序&#xff0c;做翻译…

在 4G 内存的机器上,申请 8G 内存会怎么样?

在 4GB 物理内存的机器上&#xff0c;申请 8G 内存会怎么样&#xff1f; 这个问题在没有前置条件下&#xff0c;就说出答案就是耍流氓。这个问题要考虑三个前置条件&#xff1a; 操作系统是 32 位的&#xff0c;还是 64 位的&#xff1f;申请完 8G 内存后会不会被使用&#x…

cmd命令教程

小提示&#xff1a; 在本文中&#xff0c;我将向您展示可以在 Windows 命令行上使用的 40 个命令 温馨提示&#xff1a;在本教程中学习使用适用于 Windows 10 和 CMD 网络命令的最常见基本 CMD 命令及其语法和示例 文章目录为什么命令提示符有用一、cmd是什么&#xff1f;如何在…

一年经验年初被裁面试1月有余无果,还遭前阿里面试官狂问八股,人麻了

最近接到一粉丝投稿&#xff1a;年初被裁员&#xff0c;在家躺平了6个月&#xff0c;然后想着学习下再去面试&#xff0c;现在面试了1个月有余&#xff0c;无果&#xff0c;天天打游戏到半夜&#xff0c;根本无法静下心来学习。下面是他这些天面试经常会被问到的一些问题&#…

手机解锁方法:8个顶级的 Android 手机解锁软件

一般来说&#xff0c;太简单的密码是不安全的&#xff0c;所以我们设置一个安全的密码&#xff0c;可能会稍微复杂一点。然而&#xff0c;我们可能经常会忘记复杂的密码并锁定我们的 Android 智能手机。 8个顶级的 Android 手机解锁软件 如果您遇到过这种情况并且正在寻找一种…

【Android -- 软技能】聊聊程序员的软技能

什么是软技能&#xff1f; 所谓软技能&#xff0c;就是相对于「硬技能」而言的技能&#xff0c;对于程序员来说&#xff0c;「硬技能」就是计算机专业技术能力&#xff0c;软技能则是专业之外的所有技能&#xff0c;包括职业规划能力、处理人际关系能力、专业态度、做事的方式…

linux基本功系列之uname实战

文章目录前言一. uname命令介绍二. 语法格式及常用选项三. 参考案例3.1 输出全部信息3.2 输出内核名称及版本3.3 输出网络节点的主机名3.4 输出主机硬件架构3.5 输出操作系统名称3.6 显示版本信息总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文…

初入了解——什么是VUE

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。个人主页&#xff1a;小李会科技的…

Java中的反射

类加载器&#xff08;1&#xff09;类的加载当我们的程序在运行后&#xff0c;第一次使用某个类的时候&#xff0c;会将此类的class文件读取到内存&#xff0c;并将此类的所有信息存储到一个Class对象中。说明&#xff1a;a.图中的Class对象是指&#xff1a;java.lang.Class类的…

从Linux内核中学习高级C语言宏技巧

Linux内核可谓是集C语言大成者,从中我们可以学到非常多的技巧,本文来学习一下宏技巧,文章有点长,但耐心看完后C语言level直接飙升。 本文出自:大叔的嵌入式小站,一个简单的嵌入式/单片机学习、交流小站 从Linux内核中学习高级C语言宏技巧 1.用do{}while(0)把宏包起来 …

《网络安全》零基础教程-适合小白科普

《网络安全》零基础教程 目录 目录 《网络安全》零基础教程 第1章 网络安全基础 什么是网络安全 常见的网络安全威胁 网络安全的三个基本要素 网络安全的保障措施 第2章 网络攻击类型 病毒、蠕虫、木马、后门 DoS、DDoS攻击 ​​​​​​​SQL注入、XSS攻击 ​​​…

测试背锅侠?入职软件测试后大d佬给我丢了这个bug分类分析,至今受益匪浅......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 刚成为入职&#xf…

测试场景设计

测试场景设计 又叫做场景法。其实对于场景法是测试用例中面临最多的&#xff0c;但是这种模式不是很容易总结&#xff0c;有时候是基于经验&#xff0c;有时候是我们对系统的了解。所以在这种情况下&#xff0c;我们强硬的用场景法对其进行规范。 场景法原理 现在的软件几乎…

vscode无法连接宝塔ftp排雷

宝塔面板现在使用率非常的高。今天把自己的踩坑处理方法记录一下。 在配置号宝塔面板ftp后&#xff0c;使用vscode的sftp插件&#xff0c;发现一直链接不上。一度以为自己配置文件&#xff0c;配置的参数有问题。各种度娘后&#xff0c;花了好长时间。后来发现自己陷入了误区。…

JS高级知识总结

文章目录1. this指向问题2. 对象进阶2.1 对象的定义和使用2.2 对象访问器2.2.1 Getter2.2.2 Setter2.3 对象构造器2.4 对象原型2.4.1 prototype属性2.4.2 \_\_proto\_\_ 属性2.4.3 constructor属性2.4.4 原型链2.5 Object对象2.5.1 管理对象2.5.2 保护对象3. 函数进阶3.1 函数的…

【Python】控制自己的手机拍照,并自动发送到邮箱

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 今天这个案例&#xff0c;就是控制自己的摄像头拍照&#xff0c; 并且把拍下来的照片&#xff0c;通过邮件发到自己的邮箱里。 想完成今天的这个案例&#xff0c;只要记住一个重点&#xff1a;你需要一个摄像头 思路…

8大主流编程语言的适用领域,你可能选错了语言

很多人学编程经常是脑子一热然后就去网上一搜资源就开始学习了&#xff0c;但学到了后面发现目前所学的东西并不是自己最喜欢的&#xff0c;好像自己更喜欢另一个技术&#xff0c;感觉自己学错了&#xff0c;于是乎又去学习别的东西。 结果竹篮打水一场空&#xff0c;前面所付…

蓝桥杯刷题冲刺 | 倒计时28天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.卡片2.数字三角形3.购物单4.回文日期1.卡片 题目 链接&#xff1a; 卡片 - 蓝桥云课 (lanqiao…

【计算机组成原理 - 第一章】计算机系统概论(完结)

本章参考王道考研相关课程&#xff1a; 【2021版】1.2.1_计算机硬件的基本组成_哔哩哔哩_bilibili 【2021版】1.2.2_认识各个硬件部件_哔哩哔哩_bilibili 【2021版】1.2.3_计算机系统的层次结构_哔哩哔哩_bilibili 【2021版】1.3_计算机的性能指标_哔哩哔哩_bilibili 目录 一、…
最新文章