剩余参数
大家可能遇到过这种问题,一个函数,传入参数的个数是不确定的,这就可以用ES6的剩余参数
function fn (name, ...params) {
console.log(name)
console.log(params)
}
fn ('小米', 1, 2) // 小米 [ 1, 2 ]
fn ('小米', 1, 2, 3, 4, 5) // 小米 [ 1, 2, 3, 4, 5 ]
模板字符串
以前的我,拼接字符串只能这么做
const name = '小米'
const age = '22'
console.log(name + '今年' + age + '岁啦') // 小米今年22岁啦
现在我可以这么做,会更优雅
const name = '小米'
const age = '22'
console.log(`${name}今年${age}岁啦`) // 小米今年22岁啦
箭头函数
以前我们使用普通函数
function fn () {}
const fn = function () {}
ES6新加了箭头函数
const fn = () => {}
// 如果只有一个参数,可以省略括号
const fn = name => {}
// 如果函数体里只有一句return
const fn = name => {
return 2 * name
}
// 可简写为
const fn = name => 2 * name
// 如果返回的是对象
const fn = name => ({ name: name })
普通函数和箭头函数的区别:
1、箭头函数不可作为构造函数,不能使用new
2、箭头函数没有自己的this
3、箭头函数没有arguments对象
4、箭头函数没有原型对象
ES5的 Array.reduce
- 第一个参数callback函数: pre为上次return的值,next为数组的本次遍历的项
- 第二个参数为初始值,也是第一个pre
举3个例子:
// 计算 1 + 2 + 3 + 4 + 5
const reduceArr = [1, 2, 3, 4, 5]
const sum = reduceArr.reduce((pre, next) => {
return pre + next
}, 0)
console.log(sum) // 15
// 统计元素出现个数
const nameArr = ['小米', '小工', '小米', '小米', '科比']
const totalObj = nameArr.reduce((pre, next) => {
if (pre[next]) {
pre[next]++
} else {
pre[next] = 1
}
return pre
}, {})
console.log(totalObj) // { '小米': 3, 小工: 1, '科比': 1 }
var numbers = [65, 44, 12, 4];
function getSum(total, num) {
console.log(total, num)
return total + num;
}
numbers.reduce(getSum);
对象属性同名简写
以前同名属性需要这么写
const name = '小明'
const age = '22'
const obj = {
name: name,
age: age
}
console.log(obj) // { name: '小明', age: '22' }
ES6新增语法,只需这么写
const name = '小明'
const age = '22'
// 属性同名可简写
const obj = {
name
age
}
console.log(obj) // { name: '小明', age: '22' }
promise all方法
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
如果所有Promise都成功,则返回成功结果数组
如果有一个Promise失败,则返回这个失败结果
// 如果全都为成功
function fn(time) {
return new Promise((resolve, reject) => {
console.log(88)
setTimeout(() => {
resolve(`${time}毫秒后我成功啦!!!`)
}, time)
})
}
Promise.all([fn(2000), fn(3000), fn(1000)]).then(res => {
// 3秒后输出 [ '2000毫秒后我成功啦!!!', '3000毫秒后我成功啦!!!', '1000毫秒后我成功啦!!!' ]
console.log(res)
}, err => {
console.log(err)
})
// 如果有一个失败
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
}, time)
})
}
Promise.all([fn(2000, true), fn(3000), fn(1000, true)]).then(res => {
console.log(res)
}, err => {
console.log(err) // 3秒后输出 '3000毫秒后我失败啦!!!'
})
race方法
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
- 哪个Promise最快得到结果,就返回那个结果,无论成功失败
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
}, time)
})
}
Promise.race([fn(2000, true), fn(3000), fn(1000)]).then(res => {
console.log(res)
}, err => {
console.log(err) // 1秒后输出
})
class
以前咱们使用构造函数生成对象,这么做
function Person(name) {
this.name = name
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const kobe = new Person('科比')
kobe.sayName() // 科比
而有了ES6的class可以这么做
class Person {
constructor(name) {
// 构造器
this.name = name
}
sayName() {
console.log(this.name)
}
}
const kobe = new Person('科比')
kobe.sayName() // 科比
值得一提的是,class本质也是function,class是function的语法糖
class Person {}
console.log(typeof Person) // function
除了以上,还需要知道class的以下知识点
静态属性和静态方法,使用static定义的属性和方法只能class自己用,实例用不了
class Person {
constructor(name) {
this.name = name
}
static age = 22
static fn() {
console.log('哈哈')
}
}
console.log(Person.age) // 22
Person.fn() // 哈哈
const sunshine_lin = new Person('小米')
console.log(sunshine_lin.age) // undefined
sunshine_lin.fn() // fn is not a function
extend继承
class Animal {
constructor(name, age) {
this.name = name
this.age = age
}
}
class Cat extends Animal {
say() {
console.log(this.name, this.age)
}
}
const cat = new Cat('ketty', 5) // 继承了Animal的构造器
cat.say() // ketty 5
解构赋值
以前想提取对象里的属性需要这么做
const obj = {
name: '小米',
age: 22,
gender: '男'
}
const name = obj.name
const age = obj.age
const gender = obj.gender
console.log(name, age, gender) // 小米 22 男
ES6新增了解构赋值的语法
const obj = {
name: '小米',
age: 22,
gender: '男',
doing: {
morning: '摸鱼',
afternoon: '摸鱼',
evening: 'sleep'
}
}
const { name, age, gender } = obj
console.log(name, age, gender) // 小米 22 男
// 解构重名
const { name: myname } = obj
console.log(myname) // 小米
// 嵌套解构
const { doing: { evening } } = obj
console.log(evening) // sleep
也可以进行数组的解构
const arr = [1, 2, 3]
const [a, b, c] = arr
console.log(a, b, c) // 1 2 3
// 默认赋值
const [a, b, c, d = 5] = arr
console.log(a, b, c, d) // 1 2 3 5
// 乱序解构
const { 1: a, 0: b, 2: c } = arr
console.log(a, b, c) // 2 1 3
find 和 findIndex
- find:找到返回被找元素,找不到返回undefined
- findIndex:找到返回被找元素索引,找不到返回-1
const findArr = [
{ name: '科比', no: '24' },
{ name: '罗斯', no: '1' },
{ name: '利拉德', no: '0' }
]
const kobe = findArr.find(({ name }) => name === '科比')
const kobeIndex = findArr.findIndex(({ name }) => name === '科比')
console.log(kobe) // { name: '科比', no: '24' }
console.log(kobeIndex) // 0
for of 和 for in
- for in :遍历方法,可遍历对象和数组
- for of :遍历方法,只能遍历数组,不能遍历对象
先看for in:
const obj = { name: '小米', age: 22, gender: '男' }
const arr = [1, 2, 3, 4, 5]
for(let key in obj) {
console.log(key)
}
name
age
gender
for(let index in arr) {
console.log(index)
}
0 1 2 3 4
再看 for of:
for(let item of arr) {
console.log(item)
}
1 2 3 4 5
Set 和 Map
Set
先说说Set的基本用法
// 可不传数组
const set1 = new Set()
set1.add(1)
set1.add(2)
console.log(set1) // Set(2) { 1, 2 }
// 也可传数组
const set2 = new Set([1, 2, 3])
// 增加元素 使用 add
set2.add(4)
set2.add('小米')
console.log(set2) // Set(5) { 1, 2, 3, 4, '小米' }
// 是否含有某个元素 使用 has
console.log(set2.has(2)) // true
// 查看长度 使用 size
console.log(set2.size) // 5
// 删除元素 使用 delete
set2.delete(2)
console.log(set2) // Set(4) { 1, 3, 4, '小米' }
再说说Set的不重复性
// 增加一个已有元素,则增加无效,会被自动去重
const set1 = new Set([1])
set1.add(1)
console.log(set1) // Set(1) { 1 }
// 传入的数组中有重复项,会自动去重
const set2 = new Set([1, 2, '小米', 3, 3, '小米'])
console.log(set2) // Set(4) { 1, 2, '小米', 3 }
Set的不重复性中,要注意引用数据类型和NaN
// 两个对象都是不用的指针,所以没法去重
const set1 = new Set([1, {name: '小米'}, 2, {name: '小米'}])
console.log(set1) // Set(4) { 1, { name: '小米' }, 2, { name: '小米' } }
// 如果是两个对象是同一指针,则能去重
const obj = {name: '小米'}
const set2 = new Set([1, obj, 2, obj])
console.log(set2) // Set(3) { 1, { name: '小米' }, 2 }
咱们都知道 NaN !== NaN,NaN是自身不等于自身的,但是在Set中他还是会被去重
const set = new Set([1, NaN, 1, NaN])
console.log(set) // Set(2) { 1, NaN }
利用Set的不重复性,可以实现数组去重
const arr = [1, 2, 3, 4, 4, 5, 5, 66, 9, 1]
// Set可利用扩展运算符转为数组哦
const quchongArr = [...new Set(arr)]
console.log(quchongArr) // [1, 2, 3, 4, 5, 66, 9]
Map
Map对比object最大的好处就是,key不受类型限制
// 定义map
const map1 = new Map()
// 新增键值对 使用 set(key, value)
map1.set(true, 1)
map1.set(1, 2)
map1.set('哈哈', '嘻嘻嘻')
console.log(map1) // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' }
// 判断map是否含有某个key 使用 has(key)
console.log(map1.has('哈哈')) // true
// 获取map中某个key对应的value 使用 get(key)
console.log(map1.get(true)) // 2
// 删除map中某个键值对 使用 delete(key)
map1.delete('哈哈')
console.log(map1) // Map(2) { true => 1, 1 => 2 }
// 定义map,也可传入键值对数组集合
const map2 = new Map([[true, 1], [1, 2], ['哈哈', '嘻嘻嘻']])
console.log(map2) // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' }
ES7 includes
传入元素,如果数组中能找到此元素,则返回true,否则返回false
const includeArr = [1, 2 , 3, '小米', '科比']
const isKobe = includeArr.includes('科比')
console.log(isKobe) // true
跟indexOf很像,但还是有区别的
const arr = [1, 2, NaN]
console.log(arr.indexOf(NaN)) // -1 indexOf找不到NaN
console.log(arr.includes(NaN)) // true includes能找到NaN
ES7 求幂运算符
以前求幂,我们需要这么写
const num = Math.pow(3, 2) // 9
ES7提供了求幂运算符:**
const num = 3 ** 2 // 9
ES8 Object.values
可以用来获取对象的value的集合
const obj = {
name: '小米',
age: 22,
gender: '男'
}
const values = Object.values(obj)
console.log(values) // [ '小米', 22, '男' ]
ES8 Object.entries
可以用来获取对象的键值对集合
const obj = {
name: '小米',
age: 22,
gender: '男'
}
const entries = Object.entries(obj)
console.log(entries)
// [ [ 'name', '小米' ], [ 'age', 22 ], [ 'gender', '男' ] ]
ES8 async/await
这个是很常用的语法了,我的理解就是:以同步方式执行异步操作
我们平时可能会遇到这种场景,接口一,请求到数据一,而数据一被当做请求二的参数去请求数据二,我们会用Promise这么做
function fn() {
// 模拟第一次请求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5)
}, 1000)
}).then(res => {
// 模拟第二次请求
new Promise((resolve, reject) => {
setTimeout(() => {
// 拿第一次请求的数据去乘10,当做第二次请求的数据
resolve(res * 10)
}, 2000)
}).then(sres => {
console.log(sres)
})
})
}
fn() // 1 + 2 = 3 3秒后输出 50
这样的嵌套是不美观的,如果有很多个接口,那就会嵌套很多层,此时我们可以使用async/await来以同步方式执行异步,注意以下几点:
await只能在async函数里使用
await后面最好接Promise,如果后面接的是普通函数则会直接执行
async函数返回的是一个Promise
function fn1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5)
}, 1000)
})
}
function fn2 (data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data * 10)
}, 2000)
})
}
async function req () {
// 同步方式执行异步,像排队一样
const data1 = await fn1() // 等待1秒后返回数据再往下执行
const data2 = await fn2(data1) // 拿data1去请求2秒后,往下走
console.log(data2) // 总共3秒后 输出 50
}
req()
ES9 for await of
我们来看以下场景哈
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒后我成功啦!!!`)
}, time)
})
}
fn(3000).then(res => console.log(res))
fn(1000).then(res => console.log(res))
fn(2000).then(res => console.log(res))
结果是
1000毫秒后我成功啦!!!
2000毫秒后我成功啦!!!
3000毫秒后我成功啦!!!
但是我想要这个结果
3000毫秒后我成功啦!!!
1000毫秒后我成功啦!!!
2000毫秒后我成功啦!!!
第一时间我们肯定想到的是async/await
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒后我成功啦!!!`)
}, time)
})
}
async function asyncFn () {
// 排队
const data1 = await fn(3000)
console.log(data1) // 3秒后 3000毫秒后我成功啦!!!
const data2 = await fn(1000)
console.log(data2) // 再过1秒 1000毫秒后我成功啦!!!
const data3 = await fn(2000)
console.log(data3) // 再过2秒 2000毫秒后我成功啦!!!
}
但是上面代码也是有缺点的,如果有几十个,那不是得写几十个await,有没有一种方法可以通过循环来输出呢?
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒后我成功啦!!!`)
}, time)
})
}
async function asyncFn () {
const arr = [fn(3000), fn(1000), fn(1000), fn(2000), fn(500)]
for await (let x of arr) {
console.log(x)
}
}
asyncFn()
3000毫秒后我成功啦!!!
1000毫秒后我成功啦!!!
1000毫秒后我成功啦!!!
2000毫秒后我成功啦!!!
500毫秒后我成功啦!!!
ES10 Array.flat
有一个二维数组,我想让他变成一维数组:
const arr = [1, 2, 3, [4, 5, 6]]
console.log(arr.flat()) // [ 1, 2, 3, 4, 5, 6 ]
还可以传参数,参数为降维的次数
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
console.log(arr.flat(2))
[
1, 2, 3, 4, 5,
6, 7, 8, 9
]
如果传的是一个无限大的数字,那么就实现了多维数组(无论几维)降为一维数组
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]]
console.log(arr.flat(Infinity))
[
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12
]
ES10 BigInt
BigInt是ES10新加的一种JavaScript数据类型,用来表示表示大于 2^53 - 1 的整数,2^53 - 1是ES10之前,JavaScript所能表示最大的数字
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// 9007199254740991n
const hugeString = BigInt("9007199254740991");
// 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// 9007199254740991n
哦对了,既然是JavaScript新的数据类型,那他的typeof是啥?
const bigNum = BigInt(1728371927189372189739217)
console.log(typeof bigNum) // bigint
所以以后面试官问你JavaScript有多少种数据类型,别傻傻答6种了,要答8种,把ES6的Symbol和ES10的BigInt也加上去
ES10 Object.fromEntries
前面ES8的Object.entries是把对象转成键值对数组,而Object.fromEntries则相反,是把键值对数组转为对象
const arr = [
['name', '小米'],
['age', 22],
['gender', '男']
]
console.log(Object.fromEntries(arr)) // { name: '小米', age: 22, gender: '男' }
他还有一个用处,就是把Map转为对象
const map = new Map()
map.set('name', '小米')
map.set('age', 22)
map.set('gender', '男')
console.log(map) // Map(3) { 'name' => '小米', 'age' => 22, 'gender' => '男' }
const obj = Object.fromEntries(map)
console.log(obj) // { name: '小米', age: 22, gender: '男' }
ES10 String.trimStart && String.trimEnd
咱们都知道JavaScript有个trim方法,可以清除字符串首尾的空格
const str = ' 小米 '
console.log(str.trim()) // '小米'
trimStart和trimEnd用来单独去除字符串的首和尾的空格
const str = ' 小米 '
// 去除首部空格
console.log(str.trimStart()) // '小米 '
// 去除尾部空格
console.log(str.trimStart()) // ' 小米'
ES11 Promise.allSettled
ES11新增的Promise的方法
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
把每一个Promise的结果,集合成数组,返回
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
}, time)
})
}
Promise.allSettled([fn(2000, true), fn(3000), fn(1000)]).then(res => {
console.log(res)
// 3秒后输出
[
{ status: 'fulfilled', value: '2000毫秒后我成功啦!!!' },
{ status: 'rejected', reason: '3000毫秒后我失败啦!!!' },
{ status: 'rejected', reason: '1000毫秒后我失败啦!!!' }
]
})
ES11 ?. 和 ??
先说说?.,中文名为可选链
比如我们需要一个变量,是数组且有长度,才做某些操作
const list = null
// do something
if (list && list.length) {
// do something
}
// 使用可选链
const list = null
// do something
if (list?.length) {
// do something
}
比如有一个对象,我要取一个可能不存在的值,甚至我们都不确定obj是否存在
const obj = {
cat: {
name: '哈哈'
}
}
const dog = obj && obj.dog && obj.dog.name // undefined
// 可选链
const obj = {
cat: {
name: '哈哈'
}
}
const dog = obj?.dog?.name // undefined
比如有一个数组,我不确定它存不存在,存在的话就取索引为1的值
const arr = null
// do something
const item = arr && arr[1]
// 可选链
const arr = null
// do something
const item = arr?.[1]
比如有一个函数,我们不确定它存不存在,存在的话就执行它
const fn = null
// do something
const res = fn && fn()
// 可选链
const fn = null
// do something
const res = fn?.()
再说说??,中文名为空位合并运算符
请看以下代码,咱们使用||运算符,只要左边是假值,就会返回右边的数据
const a = 0 || '小米' // 小米
const b = '' || '小米' // 小米
const c = false || '小米' // 小米
const d = undefined || '小米' // 小米
const e = null || '小米' // 小米
而??和||最大的区别是,在??这,只有undefined和null才算假值
const a = 0 ?? '小米' // 0
const b = '' ?? '小米' // ''
const c = false ?? '小米' // false
const d = undefined ?? '小米' // 小米
const e = null ?? '小米' // 小米
ES12 Promise.any
E12新增的Promise的方法
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
如果有一个Promise成功,则返回这个成功结果
如果所有Promise都失败,则报错
// 当有成功的时候,返回最快那个成功
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
}, time)
})
}
Promise.any([fn(2000, true), fn(3000), fn(1000, true)]).then(res => {
console.log(res) // 1秒后 输出 1000毫秒后我成功啦
}, err => {
console.log(err)
})
// 当全都失败时
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
}, time)
})
}
Promise.any([fn(2000), fn(3000), fn(1000)]).then(res => {
console.log(res)
}, err => {
console.log(err) // 3秒后 报错 all Error
})
ES12 数字分隔符
数字分隔符可以让你在定义长数字时,更加地一目了然
const num = 1000000000
// 使用数字分隔符
const num = 1_000_000_000
ES12 ||= 和 &&=
或等于(||=) a ||= b 等同于 a || (a = b);
且等于(&&=) a &&= b 等同于 a && (a = b);
不知道是ES几 对象动态属性
我们经常碰到这样的问题,无论是在微信小程序还是React中,我们需要根据某个条件去修改某个数据
if (type === 'boy') {
this.setData({
boyName: name
})
} else if (type === 'girl') {
this.setData({
girlName: name
})
}
我也不知道这个新特性叫啥,我就自己取名叫属性动态属性哈哈哈
this.setData({
[`${type}Name`]: name
})