文章目录
咱就是说,现如今没有人不用ES6吧,甭管是vue还是react,但凡需要JS都会用到ES6,那我整理的几点就是在我近期项目中比较常用而且好用的语法,有需要的就一起看看吧。Let’s go!
1.解构赋值
作用:
解构赋值是对赋值运算符的扩展,允许按照一定的模式,从数组或对象中取值,对变量进行赋值
基本用法:
// ----------数组--------
let a=1;b=2;c=3 // 正常定义变量赋值
------------
let [a, b, c] = [1, 2, 3] // es6对数组解构赋值
a // 1 b // 2 c // 3
let [x, , y] = [1, 2, 3] // 个别使用
console.log(x) // 1
console.log(y) // 3
let [foo, [[bar], baz]] = [1, [[2], 3]] // 嵌套数组
console.log(foo) //1
console.log(bar) //2
console.log(baz) //3
let [a]=[] // 解构失败
console.log(a) // undefined
let [x, y, ...z] = ['a'] // 结合展开运算符使用
console.log(x) // "a"
console.log(y) // undefined
console.log(z) // []
let [a = 8,b='bb',c='cc',d='dd',e] = ['aa', undefined,1,null] //默认值
console.log(a) // 'aa'
console.log(b) // 'bb'
console.log(c) // 1
console.log(d) // null
console.log(e) // undefined
function f() {console.log('aaa')} // 默认值为表达式(惰性求值)
let [x = f()] = [1]
console.log(x) // 1
// ----------对象--------
数组是按下标进行排序的,取值由位置决定,但是对象取值由属性名决定.
let { a, b } = { a: 'aaa' } // es6对对象解构赋值(缩写)
console.log(a) // 'aaa'
console.log(b) // undefined
let { a: baz } = { a: 'aaa', b: 'bbb' } // 变量名和属性名不同
console.log(baz) // "aaa"
console.log(a) // error: a is not defined
底层逻辑是先找到a属性,然后再将a对应的值赋值给baz,所以真正被赋值的是baz而不是a
a也作为变量:let { a,a: baz } = { a: 'aaa', b: 'bbb' }
var {x, y = 5} = {x: 1} // 默认值
x // 1
y // 5
注意点:
1.无论是否完全解构,都是左边的变量被赋予右侧数据中对应的值
2.不要将{}放在行首.定义和解构赋值放两行会报错,js解析会把{}解析成代码块
let x
{x} = {x: 1} // 错误的写法
let {x} = {x: 1} // 正确
3.字符串也可以进行结构赋值,不过会进行隐式转换为类似数组的对象.const [a, b, c, d, e] = 'hello'
4.一些常用的方法也可以使用,比如Math.round
5.遍历 Map 结构时配合解构赋值方便获取键名和键值
项目常用:
1:传参时.比如行内事件需要传行内数据,但是只使用row对象里的MAIN_ID,为了便于方法里使用就可以用解构
2:提取数据. 使用接口返回对象中的data数据,解构后就不需要每次res.bean.data使用
3:按需引用指定方法import { lineOrg } from"@/api/publicApi"-
// 正常编码
getData (row.MAIN_ID) {
findRandomMatch({ MAIN_ID:row.MAIN_ID }).then(res => {
tableData = res.bean.data
getSpanArr(res.bean.data)
})
}
// 使用解构赋值
getData ({MAIN_ID}) {
findRandomMatch({ MAIN_ID }).then(({ bean:{data} }) => {
tableData = data
getSpanArr(data)
})
}
2.展开运算符...
作用:
把数组或对象内容展开便于操作
项目常用:
1:展开赋值拷贝数据
2:对象或数组合并
// 正常编码
------------分开使用对象中的不同数据
const NAME= queryForm.RANINSTASKNAME
const copyData = {
CREATE_DATE_START: queryForm.CREATE_DATE_START,
CREATE_DATE_END: queryForm.CREATE_DATE_END,
EXTRACTAUTH: queryForm.EXTRACTAUTH,
EXTRACTAUTH_ID: queryForm.EXTRACTAUTH_ID,
RANINSPLANTYPE: queryForm.RANINSPLANTYPE,
}
------------合并两个对象数据进行传参
let data=queryForm
data.pageNum=page.pageNum
data.pageSize=page.pageSize
submitQuery(data)
// 使用展开运算符
const {NAME,...copyData} = ...queryForm //拷贝
submitQuery({...page, ...queryForm }) //合并传参
注意点:
该拷贝是浅拷贝,需要注意使用类型,如果queryForm里是复杂数据类型,则可能会产生问题,需要使用深拷贝(例如JSON.parse(JSON.stringify(数据)))
// 可以将字符串转为真正的数组
let arr=[...'name']
console.log(arr) // [ 'n', 'a', 'm', 'e' ]
3.forEach数组遍历
作用
用于调用数组的每个元素,并将元素传递给回调函数。
项目常用
const data=[{name:'a',age:3},{name:'b',age:4},{name:'c',age:5}]
let arr=[];arr1=[];arr2=[]
// 常用for循环
for (let i = 0; i <data.length; i++) {
arr.push(data[i])
arr1.push(data[i].name)
arr2.push(data[i].age)
}
// foreach
data.forEach(item=>{
arr .push(item)
arr1.push(item.name)
arr2.push(item.age)
})
注意点
const arr=new Array(100000000)
console.time('forEach')
arr.forEach(item=>{})
console.timeEnd('forEach') //forEach: 3643.858ms
console.time('for')
for(let i=0;i<arr.length;i++){ }
console.timeEnd('for') //for: 69.368ms
性能比较:一般情况下for > forEach
for:for循环没有额外的函数调用栈和上下文,实现比较简单。
forEach:对于forEach来说,它的函数签名中包含了参数和上下文,所以性能会低于 for 循环。
不能使用break,continue语句跳出循环,或者使用return.可以用try catch跳出或者some find方法替代foreach
4.其余常用数组方法
// includes (用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false)
const array1 = [1, 2, 3]
console.log(array1.includes(2)) // true
// indexOf (返回数组中第一次出现给定元素的下标,如果不存在则返回 -1)
<el-input
v-model="queryForm.XIAFA_ORG_ID_NAME"
placeholder="下发任务机构"
readonly
:disabled="$store.state.userInfo.userInfo.roleId.indexOf('9901') == -1? true : false"
@click.native="getIndustryOne()">
<i class="el-icon-search" slot="suffix" />
</el-input>
// lastIndexOf (返回数组中给定元素最后一次出现的索引,如果不存在则返回 -1。该方法从 fromIndex 开始向前搜索数组)
const animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo']
console.log(animals.lastIndexOf('Dodo')) // 3
// filter (过滤满足条件的数据,返回给定数组的一部分的浅拷贝,不改变原数组)
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']
const result = words.filter(word => word.length > 6)
console.log(result) // [ 'exuberant', 'destruction', 'present' ]
// some (测试数组中是否至少有一个元素通过了由提供的函数实现的测试。如果在数组中找到一个元素使得提供的函数返回 true,则返回 true;否则返回 false。它不会修改数组)
const array = [1, 2, 3, 4, 5]
const even = item=> item % 2 === 0
console.log(array.some(even)) // true
// every (方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值)
const arr=[1,5,9,10,-3,12]
let res=arr.every(item=>item>0)
console.log(res) // false
//flat(depth) (创建一个新的数组,并根据指定深度递归地将所有子数组元素拼接到新的数组中;depth是要提取嵌套数组的结构深度,默认值为 1)
)
let arr = [1,2,[3,[4,[5]]]]
const res = arr.flat() // res [ 1, 2, 3, [ 4, [ 5 ] ] ]
const res1 = arr.flat(2) // res1 [ 1, 2, 3, 4, [ 5 ] ]
const res2=arr.flat(Infinity) // res2 [ 1, 2, 3, 4, 5 ] (Infinity:扁平化最深层数组)
// map (创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成)
const arr = [1, 4, 9, 16]
const map1 = arr.map(x => x * 2)
console.log(map1) // [ 2, 8, 18, 32 ]
// flatMap (方法对数组中的每个元素应用给定的回调函数,然后将结果展开一级,返回一个新数组。它等价于在调用 map() 方法后再调用深度为 1 的 flat() 方法(arr.map(...args).flat()),但比分别调用这两个方法稍微更高效一些。)
const arr1 = [1, 2, 1]
const result = arr1.flatMap((num) => (num === 2 ? [2, 2] : 1))
console.log(result) // [ 1, 2, 2, 1 ]
等价于先arr1.map((num) => (num === 2 ? [2, 2] : 1))得到[ 1, [ 2, 2 ], 1 ],然后再进行flat()得到 [ 1, 2, 2, 1 ]
5.箭头函数
含义
是比较简洁但是没有this的函数
使用
// 匿名函数
function (num){
return num+10
}
// 简写箭头函数,相当于上面的函数
num=>num+10
--------------简写
//1.参数只有一个可以省略()
(num,num1)=>num+num1 // 传参为多个
()=>886 //没有传参
//2.只有一个表达式可以省略{}和return
num=>{
if(num%2==0) return true
else return false
}
项目常用
//template里组件中的方法可以使用
<el-table :data="tableData"
@selection-change="(val)=>{selections = val}">
</el-table>
// data中定义变量可使用
data(){
return{
startOptions: {
disabledDate: (time) => {
if (this.queryForm.STATE_DATE_END) {
return (time.getTime() > new Date(this.queryForm.STATE_DATE_END).getTime())}
}
}
}
}
//methods方法里使用
methods: {
handleAdd(selection) {
this.$nextTick(() => {
this.$refs['form'].clearValidate()
})
if (this.isSetSub) {
findExDetail({ MAIN_ID: this.MAIN_ID }).then(res => {
this.form.tableData = res.bean.detailList
})
} else {
let list = JSON.parse(JSON.stringify(selection))
list.forEach((item) => {
this.$set(item, 'EXT_TYPE', '2')
this.form.tableData.push(item)
})
}
}
}
注意点
箭头函数是没有this的,所以它只有继承,它的this指向外层调用者.这一特质就导致了某些地方使用会出现问题.比如methods里的方法不可以使用箭头函数(方法里面可以),watch等周期钩子函数不可以使用.
// 匿名函数
let obj = {
name:'指向调用这个函数的对象'
fn: function () {
console.log(this)
}
}
obj.fn() //返回obj对象
// 箭头函数
let obj = {
name:'指向最近的外层作用域中的this所指对象'
fn: () => {
console.log(this)
}
}
obj.fn() //返回vue实例对象
// 函数嵌套
let obj = {
name:'指向最近的外层作用域中的this所指对象'
fn: function () {
return () => {
console.log(this)
}
}
}
obj.fn()() //返回obj对象
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时函数 立即执行函数 | window |
改变函数内部的this指向的方法
// 改变函数内部的this指向的方法
// call (第一个参数是修改后的this指向,后面是要传入的参数)
call() 允许为不同的对象分配和调用属于一个对象的函数/方法,可以改变其this指向.多个传参逗号分隔
应用场景:常用于做继承使用
let obj={name:'call'}
function fn(a,b){
let sum=a+b
console.log(this)
console.log(sum)
}
function fn1(){ }
fn(1,2) // this指向window,结果为3
fn.call(obj,4,5) // 这里this指向的是对象obj,结果为9
fn.call(fn1,9,3) //this指向函数fn1,运行结果为12
// apply(第一个参数是修改后的this指向,后面是要传入的参数)
apply()也是调用函数的方式,可以改变this的指向,不过传参要以数组的方法
应用场景:经常与数组有关,可以调用Math内置对象里的方法,通过apply传递参数的特性来比较数组元素
let obj={name:'call'}
function fn(a,b){
let sum=a+b
console.log(this)
console.log(sum)
}
fn(1,2) // this指向window,结果为3
fn.apply(obj,[4,5]) // 这里this指向的是对象obj,结果为9
常用于数组处理
1:取最小值 Math.min()参数不能是数组,可以使用apply帮助处理(此处使用展开运算符也可以快速处理 const min=Math.min(...arr))
const arr=[5,8,12,6,48,1,23]
const min = Math.min.apply(null, arr)
2:合并数组,可以使用push循环操作,也可以使用apply
Array.prototype.push.apply(arrA, arrB) //将数组arrB push到数组 arrA中
// bind
bind()不会调用函数,但是可以改变函数内部this指向,返回的是原函数改变this后产生的心函数
应用场景:不调用函数,但是需要改变this指向的情况,比如要改变定时器里的this,可以直接在函数外面使用bind修改指向问题,并且重新生成计时器方法.
var btns = document.querySelectorAll('button') //需求:点击按钮,将按钮变为不可编辑,3s后恢复
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
this.disabled = true
setTimeout(function () { //计时器函数里的this指向window
this.disabled = false
}.bind(this), 3000)
}
}
讲解:第一个this指向的是调用者btns[i],第二个计时器里的this指向的是window,如果不将后者this指向修改则会出现问题
方法 | 共同点 | 不同点 | 应用场景 |
---|---|---|---|
call | 都可以改变this指向 | 调用函数,传参逗号分隔 | 常用于继承 |
apply | 都可以改变this指向 | 调用函数,传参数组传递 | 常用于和数组相关 |
bind | 都可以改变this指向 | 不会调用函数,传参逗号分隔 | 只修改指,比如修改定时器内部的指向 |
6.promise和async/await
作用
都是为了解决异步回调
含义
1:async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果.
2:async函数返回值就是Promise对象,await命令就是内部then命令的语法糖.函数执行的时候,一旦遇到await就先返回,等到异步操作完成,才会运行await后面的语句
async实现原理
// async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。
async function fn(args) {
...
}
// 等同于
function fn(args) {
return spawn(function* () {
...
})
}
Generator函数就是为了解决异步问题出现的.普通函数调用会立刻全部执行完,而Generator可以暂停并且不一定立即把所有代码执行完.
语法上它是一个状态机,封装了多个内部状态.而Generator 函数返回的是遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志.
注意点
1:promise.all关联性较强,可能会影响对应模块的使用感受,使用前要确认
2:await命令只能用在async函数中,否则会报错
3:async/await是语法糖,本质还是promise.最大的特点就是将异步强行转换为同步处理,要等await运行完才会处理下面的.
4:await命令后面的Promise对象,运行结果可能是rejected,使用try catch则可以处理返回的promise对象状态为rejected的情况
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
)
//reject Error: 出错了
项目常用
// Promise一般都会封装好,我们在调取接口时常用以下三个语法糖(then catch finally)
submitQuery(data) {
this.loading = true
api.post('/JgsxqdController/findDeleteDetail', {...data}).then((res) => {
this.num++
this.ruleForm = res.bean
}).catch(() => {
this.num=0
}).finally(()=>{
this.loading = false
})
}
// async/await
async submitQuery () {
try {
const { bean: { total, listJBXX } } = await findZfzkList({ ...this.form, ...this.page, create_org: this.id })
this.num++
this.tableData = listJBXX
this.page.total = total
} catch (error) {
this.num=0
}
}
7.delete操作符
作用
通常用来删除对象的属性
使用
let obj={a:1}
delete obj.a
console.log(obj.a) //undefined
项目常用
//要删除有数据比较多的childList属性时就可以使用
delete this.selectData.childList
注意点
1:是彻底删除该属性,非置空
2:不可删除一般的变量或者函数,delete这些会返回false
3:删除数组中的元素,元素实际不存在该数组中了,但是长度不会改变
const arr = ['a','b','c','d','e']
delete arr[4] // true
console.log(arr) //[ 'a', 'b', 'c', 'd', <1 empty item> ]
console.log(arr.length) //5
console.log(arr.indexOf('e')) //false
console.log(arr[4]) //undefined