关于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类似,用于声明变量
特性:
let
不能重复声明变量,var
可以重复声明变量;- 块级作用域,
es5
中存在全局作用域、函数作用域、eval
作用域;es6
中引入了块级作用域,let
声明的变量在块级作用域{}
内有效 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 ifor(let i = 0; i < items.length; i++){items[i].onclick = function(){items[i].style.background = 'pink'}}/*相当于在3个块级作用域内分别声明了i{let i = 0items[i].onclick = function(){items[i].style.background = 'pink'}}{let i = 1items[i].onclick = function(){items[i].style.background = 'pink'}}{let i = 2items[i].onclick = function(){items[i].style.background = 'pink'}}*//*// 遍历并绑定事件 遍历时var ifor(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 用于声明常量
注意事项:
- 一定要赋初始值
- 一般常量使用大写(属于编程规范)
- 常量值不能修改
- 存在块级作用域
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错(因为引用数据类型保存的是内存地址,所以声明数组和对象时可以使用
const
声明,以此保证其保存的内存地址不变)
2.解构赋值
ES6
允许按照一定模式从数组和对象中提取值,对变量进行赋值
1) 数组的解构
const Web = ['html', 'css', 'javascript']
let [tool1, tool2, tool3] = Webconsole.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} = liMingconsole.log(name) // 'liMing'
console.log(age) // '22'
console.log(tell) // f(){...}
tell() // I am liMing
3.模板字符串
特性:
- 可以直接进行变量拼接
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 = namethis.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 definedlet 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*nconsole.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指向windowthis.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个元素
应用场景:
- 数组的合并
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)
- 数组的克隆
const STUDENTS1 = ['小明','小芳','小红']const PUPIL = [...STUDENTS1] // 注意:如果数组内元素是引用类型,拷贝的是内存地址,为浅拷贝
console.log('PUPIL----',PUPIL)
- 将伪数组转为真正的数组
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特点
Symbol
的值是唯一的,用来解决命名冲突的问题Symbol
值不能与其他数据进行运算,也不能与自己进行运算,譬如+、-、*、/、比较运算Symbol
定义的对象属性不能使用for…in
遍历,但是可以使用Reflect.ownKeys
来获取对象的所有键名
创建Symbol
- 通过
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
- 通过
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
值,指向语言内部使用的方法,比如
Symbol.hasInstance
当其他对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法
class Person{static [Symbol.hasInstance](param){console.log('param----', param)console.log('检测类型')}}let o = {}console.log(o instanceof Person)// param---- {}// 检测类型// false
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]]
Symbol.unscopables
该对象指定了使用with
关键字时,哪些属性会被with
环境排除Symbol.match
当执行str.match(myObject)
时,如果该属性存在,会调用它,返回该方法的返回值Symbol.replace
当该对象被str.replace(myObject)
方法调用时,会返回该方法的返回值Symbol.search
当该对象被str.search(myObject)
方法调用时,会返回该方法的返回值Symbol.split
当该对象被str.split(myObject)
方法调用时,会返回该方法的返回值Symbol.iterator
对象进行for ... of
循环时,会调用Symbol.iterator
方法,返回该对象的默认遍历器Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值Symbol.toStringTag
在该对象上调用toString
方法时,返回该方法的返回值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
工作原理:
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的
next
方法,指针自动指向数据结构的第一个成员 - 接下来不断调用
next
方法,指针一直往后移动,直到指向最后一个成员 - 每调用
next
方法返回一个包含value
和done
属性的对象,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 = 0return {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
遍历函数执行后返回的迭代器对象,每一次遍历的item
为yield
后的表达式或者自变量的值
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 111console.log(one) // 'bbb'let two = yield 222console.log(two) // 'ccc'let three = yield 333console.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
Promise
是ES6
引入的异步编程的新解决方案。语法上Promise
是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
Promise
构造函数:Promise(excutor){}
Promise.prototype.then
方法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)
相关文章:

关于ES6新特性的总结
目录1.let & const2.解构赋值3.模板字符串4.简化对象写法5.箭头函数6.函数参数的默认值设置7.rest参数8.扩展运算符9.SymbolSymbol特点创建SymbolSymbol使用场景Symbol内置值10.迭代器11.生成器12.Promise基本使用Promise封装读取文件Promise封装ajaxPromise.prototype.the…...

13. CSS 处理
提取 Css 成单独文件CSS 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式,加载一个页面的时候,先 html -> js -> css,会有页面闪屏现象,用户体验不好。应该是单独的 Css 文件&…...

One-hot编码
One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。 例如: 自然状态码为:000,001,010,011,100,1…...

Java中的深克隆与浅克隆
浅克隆: 实现Cloneable接口即可实现,浅克隆只对象内部的基础数据类型(包括包装类)被克隆,引用数据类型(负责对象)会被使用引用的方式传递。 简单来说,就是浅克隆属性如果是复杂对象…...

如何使用MyBatis框架实现对数据库的增删查改?
目录:1.创建MyBatis项目以及如何配置2.MyBatis操作数据库的模式3.实现增删查改注意:在我们操作数据库之前,先要保证我们已经在数据库建好了一张表。创建MyBatis项目以及如何配置我们在创建项目的时候,引入MyBatis相关依赖配置数据…...

结构体内存大小
000、前言 要想计算结构体内存大小,就会涉及到一个结构体内存对齐的问题,而不是对其成员进行简单的加运算 (1)在写本博客之前 有位同学和我讨论了一个学校的题目,题目如下: 我借这道题目问了另外一位同…...

gerrit操作和jinkens编译合入代码
gerrit 先 查看自己的push 找到后添加reviewer 填写邮箱开头就可以出来 记得1 然后send 让人review 编译不过,gerrit上查看 1.是不是checkstyle问题 2.编译不过,去jinkens查看 先retrigger重新编译 如果发现多次编译失败 则要看下console output 查…...

网络工程师面试题(面试必看)(3)
作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页 前言 本系列将会提供网络工程师面试题,由多位专家整合出本系列面试题,包含上百家面试时的问题。面试必考率达到80%,本系列共86道题…...

第N次重装系统之Ubtntu
前言又一次换了服务器,由于centOS已经完成了自己的生命周期,接下来我会转去使用Ubtntu系统。当然,大部分docker命令是不会收到影响的,但是一部分安装过程可能就要重新学习了。其实这个系统也有自己的老牌包管理器apt,所…...

一个 适用 vue3 ts h5移动端 table组件
vue3-h5-table 介绍 适用于 vue3 ts 的 h5 移动端项目 table 组件 支持 左侧固定 滑动 每行点击回调 支持 指定列排序 链接 :https://github.com/duKD/vue3-h5-table 效果 props说明minTableHeight表格最小高度 可选 默认600rowNum表格显示几行 可选 默认 6he…...

Vue.js 生产打包上线实战
项目管理后台采用Vue.js 架构,开发完毕后设计到打包上传到服务器发布。 发布成功后,总结出主要要决绝两个主要问题: 1.打包前,环境设置 2.上传到服务器,直接放在Tomcat中出现跨域访问问题。 此次项目实际处理方法为…...

C语言指针的算术运算
C语言指针的算术运算 C语言中,指针是一种非常重要的数据类型。除了可以指向特定的内存地址外,指针还可以进行算术运算。指针的算术运算包括加、减、比较等操作,下面我们将详细介绍这些运算符的使用方法,并提供实际的示例。 指针…...

快速排序/快速选择算法
一.快速排序 1.基本介绍 快速排序(Quicksort〉是对冒泡排序的一种改进,都属于交换排序。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分(每次选择中轴值),中轴值左边的元素小于中轴值,中轴值右边的元素全部大于中轴值(但不要求有序)&#x…...

【数据结构初阶】单链表面试题|内含链表带环问题
目录 前言 链表面试题 1. 删除链表中等于给定值 val 的所有节点。oj链接 2.反转一个单链表。oj链接 3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。oj链接 4. 输入一个链表,…...

一文解析ethtool 命令的使用
命令简介 ethtool命令用于查询和控制网络设备驱动程序和硬件设置,尤其是有线以太网设备,devname网卡的名称。网卡就像是交换机的一个端口,正常使用我们只是配置网卡IP地址等信息,网卡的速率、双工模式等我们并不关心。通过ethtoo…...

深度学习训练营之yolov5训练自己的数据集
深度学习训练营之训练自己的数据集原文链接环境介绍准备好数据集划分数据集运行voc_train.py遇到问题完整代码创建new_data.yaml文件模型训练时遇到的报错模型训练结果可视化参考链接原文链接 🍨 本文为🔗365天深度学习训练营 中的学习记录博客…...

Java中的AQS
文章目录什么是AQSAbstractQueuedSynchronizer方法解析自旋与阻塞ReentrantLock,Semaphore以及CountDownLatch对比ReentrantLock实现原理原理ReentrantLock源码中compareAndSetState的方法Semaphore实现原理CountDownLatch实现原理什么是AQS AQS是Java中的一个抽象…...

Spring——案例-业务层接口执行效率和AOP通知获取数据+AOP总结
执行时间获取:记录开始时间和结束时间,取差值。 这里使用环绕通知来实现。 环境准备: 项目文件结构: 业务层接口和实现类: 数据层: 采用mybatis注解开发,这里没有实现类,直接在接口方法里面实现映射。 domain层: 实现了数据库里面每一个…...

国外SEO舆情处理最佳黄金时间
在国外市场,SEO(搜索引擎优化)的舆情处理是非常重要的,因为它可以帮助提高网站的排名和流量,并且建立品牌的声誉和信誉。 然而,在什么时间进行舆情处理是一个值得探讨的问题。 在本文中,我们将…...

ROC和AUC
目录 ROC AUC ROC ROC曲线是Receiver Operating Characteristic Curve的简称,中文名为"受试者工作特征曲线"。ROC曲线的横坐标为假阳性率(False Postive Rate, FPR);纵坐标为真阳性率(True Positive Rate, TPR).FPR和TPR的计算方法分别为 F…...

Dopamine-PEG-cRGD,DOPA-PEG-cRGD,多巴胺-聚乙二醇-crgd细胞穿膜肽
名称:多巴胺-聚乙二醇-cRGD穿膜肽,多巴胺-聚乙二醇-crgd细胞穿膜肽英文名称:Dopamine-PEG-cRGD,DOPA-PEG-cRGD规格:50mg,100mg,150mg(根据要求可定制)描述:cRGD多肽序列: cyclo(RGDfK)外 观 : 半固体或固体,取决于分子量。溶解性:…...

动态规划回文子串
647. 回文子串方法:双指针回文子串有长度为奇数和偶数两种,extend(s, i, i, n); extend(s, i, i 1, n);就分别对应长度为奇数和偶数的情况class Solution { private:int extend(const string& s, int i, int j, int n) {int res 0;while (i > 0…...

windows 域控提权CVE-2014-6324CVE-2020-1472CVE-2021-42287CVE-2022-26923
一、CVE-2014-6324复现 环境:god.org域,两台主机,一台win2008域控,另一台web服务器win2008 工具:ms14-068.exe(漏洞exp) mimikatz psexec 利用条件: 1.域用户账号密码 2.获得一台主机权限(本地administ…...

1、JDK 安装 Java环境变量配置
jdk下载(Java8) (下载时间不同,小版本号会有变化,不影响后续安装) 官网下载地址:https://www.oracle.com/java/technologies/downloads/#java8-windows 下载完后安装 JDK 环境变量配置 Win…...

[c++]list模拟实现
目录 前言: 学习类的方式: 1 类成员变量 1.1 list成员变量 1.2 结点结构体变量 1.3 迭代器成员变量 2 默认函数——构造 2.1 结点结构体构造函数 2.2 list构造函数 2.3 迭代器构造函数 3 迭代器实现 3.1 list部分 3.2 迭代器结构体部分 3.2…...

实用的仓库管理软件有哪些,盘点2023年5大仓库管理软件!
对于做批发生意的老板或工厂老板来说,选择一款实用的仓库管理软件是至关重要的。仓库管理软件除了可以帮你降低仓库管理成本,提高经营管理的效率,还能够在手机上随时随地掌控仓库员工和商品的最新信息,与客户、供应商的订单情况能…...

(八十二)透彻研究通过explain命令得到的SQL执行计划(1)
今天我们正式进入研究explain命令得到的SQL执行计划的内容了,只要把explain分析得到的SQL执行计划都研究透彻,完全能看懂,知道每个执行计划在底层是怎么执行的,那么后面学习SQL语句的调优就非常容易了。 首先,我们现在…...

【Linux】旋转锁 | 读写锁
在之前的线程学习中,用到的锁都是挂起等待锁,如果申请不到锁,那就会在锁中等待; 自旋锁则不大相似 文章目录1.自旋锁1.1 概念1.2 接口1.2.1 pthread_spin_init/destroy1.2.2 pthread_spin_lock1.2.3 pthread_spin_unlock2.读写锁…...

EasyExcell导出excel添加水印
EasyExcell导出excel添加水印1、添加easyExcel相关依赖2、准备基础工具类3、创建水印handler类4、创建单元测试类WriteTest.class5、测试结果1、添加easyExcel相关依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId&…...

SpringCloud:Nacos配置管理
Nacos除了可以做注册中心,同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理…...