JS语法-ES6
1.介绍
ECMAScript 6简称ES6,是JavaScript语言的下一代标准。
2.常用属性及方法
2.1常量与变量的定义
在JavaScript中,我们一般使用var来定义变量,实际上它是有缺陷的,变量的作用域只存在于function中,在if和for中不存在。而ES6就解决了这个问题。
let来定义变量,const来定义值不变的量。可以很好的替换掉var。
注意:
a.const在定义常量时,必须赋初值;
b.const一旦定义了标识符,就不能再次赋值。
c.如果const定义的是对象,那么对象的属性值可以改变。
2.2箭头函数
语法:将原函数的“function”关键字和函数名都删掉,并使用“=>”连接参数列表和函数体,相当于匿名函数。当函数参数只有一个,括号可以省略;但是没有参数时,括号不可以省略。当代码块中只有一行代码时,可以省略大括号进行简写。
(参数列表) => {
//dosomthing
}
箭头中的this查找方式:向外层作用域中一层层查找,直到有this的定义。当然有的地方也可以对function()进行简写,如get:function()可以简写为get()。但是这种方式不属于箭头函数,是ES6的新特性。
实例1:无参函数的js版和es6版对比
var test1=function test(){ console.log(123) } var test2=()=>{ console.log(456) } //使用函数 test1() test2()
实例2:单参函数的js版和es6版对比
var test1 = function test(p) { console.log(123 + p) } var test2 = p => { console.log(456 + p) } test1('6') test2('6')
实例3:多参函数的js版和es6版对比
var test1 = function test(p, p2) { console.log(123 + p + p2) } var test2 = (p,p2) => { console.log(456 + p + p2) } test1('6', 'abc') test2('6', 'abc')
实例4:一行代码的js版和es6版对比
var test1 = function test(a, b) { return a + b } var test2 = (a, b) => a + b console.log(test1(12, 20)) console.log(test2(12, 20))
说明:当里面只有一行代码时可以使用,另外es6可以省略return关键字。
2.3幂运算**
在es6中可以使用**来进行幂运算,相当于Math.pow()
console.log(3**3)//27 console.log(2**3)//8
2.4includes()方法
用在字符串中,用于判断字符串是否包含某个字串。
string.includes(str)
用在数组中,用于判断数组是否包含某个元素。
array.includes(s)
实例1:判断字符串中是否包含子串
const str = 'abc123bchh' const str2 = 'bc' const str3 = '1234' console.log(str.includes(str2))//true console.log(str.includes(str3))//false
实例2:判断数组中是否包含某个元素
const arr = [1,2,3,5,7,6] console.log(arr.includes(9))//false console.log(arr.includes(5))//true
2.5padStart()与padEnd()方法
padStart()和padEnd()分别用来自动在头部补全和尾部补全,常用于自动补0。
string.padStart(len,str)
string.padEnd(len,str)
len表示最终的字符串的长度,是需要指定的。str是用于补全的字符串。
实例1:格式化时间,如果数字小于10则在前面补0(使用padStart)
const date = new Date(); const year = date.getFullYear() const month = (date.getMonth() + 1).toString().padStart(2, '0') const day = (date.getDate()).toString().padStart(2, '0') const time = year + "-" + month + "-" + day console.log(time)
3.模块化的导入与导出
在ES6中,可以使用模块化的导入与导出。导入使用关键字import,导出使用关键字export。
在html中,在引入js的时候,需要加上type="module"。
<script src="test.js" type="module"></script> <script src="test2.js" type="module"></script>
3.1第一种方式:确定了导出的名称
1)导出对象:使用export {} 来导出对象,大括号中填写要导出的变量名称。test.js内容如下:
const flag = true; function sum(num1, num2) { return num1 + num2; } export {flag, sum}
在test2.js中导入使用
import {flag, sum} from "./test.js" if (flag) { console.log("从test1.js导入成功") } console.log(sum(25, 30))
2)导出变量:使用export加上变量,直接导出变量。test.js内容如下:
export const message = '导出变量'; export const num = 10;
在test2.js中导入使用
import {message, num} from "./test.js"; console.log(message, num);
上面的两种方式都是通过解构赋值的方式导入的(只导入需要的),其实也可以全部导入。
import * as test from "./test.js"; console.log(test.message) console.log(test.num)
上面就是全部导入,导入后把它作为一个对象,然后通过这个对象来使用其中的属性和方法。
3.2第二种方式:使用default
有时候到导出的时候不命名,而在导入的时候让导入者自己进行命名就可以使用export default的方法导出,导入的时候import后面也不需要加{}了。。test.js内容如下:
const test = { flag: true, sum(num1, num2) { return num1 + num2; } } export default test
在test2.js中导入使用
import test from './test.js' console.log(test.sum(1, 3)) console.log(test.flag)
需要注意的是export default在同一个模块中只能存在一个,不能出现多个。
4.Promise
异步编程的解决方案,多用在网络请求中,解决回调地狱的问题。一般在异步操作中对异步操作进行封装。
只要创建了Promise对象就会立即执行异步操作,如网络请求。异步操作之后有三种状态:pending:等待,fulfill:满足,reject:拒绝。
4.1Pomise的几种使用方式
1)使用then和catch
new Promise((resolve, reject) => {
//异步操作
//data为异步操作成功返回的数据,err为异步操作失败的错误信息
if (异步操作成功) resolve(data)
else reject(err)
}).then(data => {
// 异步操作成功时若调用了resolve()方法则会进入这里执行
console.log(data)
}).catch(err => {
// 异步操作失败时若调用了reject()方法则会进入这里执行
console.log(err)
})
2)省略catch
new Promise((resolve, reject) => {
//异步操作
//data为异步操作成功返回的数据,err为异步操作失败的错误信息
if (异步操作成功) resolve(data)
else reject(err)
}).then(data => {
// 异步操作成功时若调用了resolve()方法则会进入这里执行
console.log(data)
}, err => {
// 异步操作失败时若调用了reject()方法则会进入这里执行
console.log(err)
})
4.2Promise的链式调用
异步操作中嵌套异步操作
new Promise((resolve, reject) => {
//异步操作
//data为异步操作成功返回的数据,err为异步操作失败的错误信息
if (异步操作成功) resolve(data)
else reject(err)
}).then(data => {
// 异步操作成功时若调用了resolve()方法则会进入这里执行
console.log(data)
new Promise((resolve, reject) => {
//异步操作
if (异步操作成功) resolve(data)
else reject(err)
}).then(data => {
console.log(data)
}, err => {
console.log(err)
})
}, err => {
// 异步操作失败时若调用了reject()方法则会进入这里执行
console.log(err)
})
4.3Promise中all方法
当需要同时执行两个异步操作时就可以使用all。
Promise.all([new Promise((resolve, reject) => { //异步操作1 if (异步操作成功) resolve(data) else reject(err) }), new Promise((resolve, reject) => { //异步操作2 if (异步操作成功) resolve(data) else reject(err) }) ]).then(results => { //results中包含两个操作的结果 console.log(results) })
5.async和await
//异步的方法 function test(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(2 * num) }, 2000); }) } async function testResult () { console.log('我是内部1') //把异步方法当做同步方法执行,执行完后再执行后面的代码 let result = await test(30) console.log(result) console.log('我是内部2') } testResult() /** * 打印结果:其中60是在等待2s后打印的 * 我是内部1 60 我是内部2 */
6.模板字符串
在js中,会遇到很多的在字符串拼接,其实可以使用模板,内容可以出现换行符。变量放到${}里面,最外面使用反引号(`)包裹。这个符号处于键盘esc和tab之间,英文状态下的~。
const year = 2020 const month = 08 const day = 27 //使用模板, const time = `${year}-${month}-${day}` console.log(time)//2020-8-27
7.变量的解构赋值
7.1数组的解构
const arr = ['战三', 123, '李四', 22.5] let [a, b, c, d] = arr console.log(a)//战三 console.log(b)//123 console.log(c)//李四 console.log(d)//22.5
7.2对象的解构
const person = { name: '王敏', age: 20, sum(a, b) { return a + b } } let { name, age, sum } = person console.log(name)//王敏 console.log(age)//20 console.log(sum)//[Function: sum]
let {sum}=person console.log(sum(10,20))//30
8.函数的扩展
8.1参数默认值
function add(a, b, c = 5) {
return a + b + c
}
console.log(add(4, 6, 7))//17,全部传值,就使用传递的值,4+6+7=17
console.log(add(4, 6))//15,没有传值,就使用默认值,4+6+5=15
//与解构赋值进行结合使用
const option={
host:'localhost',
username:'root',
password:'1234'
}
//解构赋值,设置参数默认值
function connect({username,password,host='127.0.0.1'}){
console.log(host)
console.log(username)
console.log(password)
}
connect(option)
8.2rest参数
function add(...args){ console.log(args) } add(1,2,3)//[ 1, 2, 3 ] add(1,2,5,8)//[ 1, 2, 5, 8 ]
9.扩展运算符...
扩展运算符( spread )是三个点(...),用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。可以用于数组的合并,类型转换等等。
9.1数组的合并
这种方式可以用来连接数组,并返回一个新的数组。通过...来识别,可以同时连接多个
let arr1 = [1, 3, 5, 6, 4] let arr2 = [7, 9, 8, 10] let arr3 = [...arr1, ...arr2] console.log(arr3)
9.2set对象转数组
set对象后面有说明,这里先使用。
//使用扩展运算符把集合转为数组 const newArr=[...new Set([1,2,5,6,2,4,6])]
10.迭代器(遍历)
10.1 原生fori的用法
const arr = ['孙悟空', '猪八戒', '沙僧', '唐僧'] for (var i = 0; i < arr.length; i++) { console.log(arr[i]) }
10.2 for of的用法
遍历数组内容。
const arr = ['孙悟空', '猪八戒', '沙僧', '唐僧'] for (let v of arr) { console.log(v)//分别打印'孙悟空','猪八戒','沙僧','唐僧' }
10.3 for in的用法
遍历数组的索引。
const arr = ['孙悟空', '猪八戒', '沙僧', '唐僧'] for (let v in arr) { console.log(v)//分别打印0,1,2,3 }
10.4 forEach的用法
可遍历数组索引和内容。
const arr = ['孙悟空', '猪八戒', '沙僧', '唐僧'] arr.forEach((item, index) => console.log(`索引:${index},内容:${item}`))
10.3 它们的区别
1)forEach 不能使用break 和return 结束并退出循环;fori、for in 和 for of 可以使用break和 return
2)for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。for of遍历的只是数组内的元素,而不包括数组的原型属性method和索引name。故for in 更适合遍历对象,for of 适合遍历数组或者类数组。
11.数据结构
11.1 Set
11.1.1声明集合
let s1=new Set()
let s2=new Set([1,2,5,6,2,4,6]) console.log(s2)//Set { 1, 2, 5, 6, 4 }
11.1.2添加元素add
s2.add('你好啊') console.log(s2)//Set { 1, 2, 5, 6, 4, '你好啊' }
11.1.3删除元素delete
const r = s2.delete(1) console.log(r)//true console.log(s2)//Set { 2, 5, 6, 4, '你好啊' }
11.1.4判断元素是否存在has
const has = s2.has('你好啊') console.log(has)//true
11.1.5清空集合clear
s2.clear() console.log(s2)//Set {}
11.1.6遍历
for (let v of s2) { console.log(v) }
11.1.7集合的应用
1)数组去重
const arr = [1, 2, 5, 6, 2, 4, 6] //使用扩展运算符把集合转为数组 const newArr = [...new Set(arr)] console.log(newArr)//[ 1, 2, 5, 6, 4 ]
2)计算两个数组的交集
const arr2 = [3, 4, 6, 7, 9] //先把数组的内容进行去重,然后使用filter方法过滤 const result = [...new Set(arr)].filter(item => new Set(arr2).has(item)) console.log(result)//[ 6, 4 ]
3)计算两个数组的差集
const result2 = [...new Set(arr)].filter(item => !new Set(arr2).has(item)) console.log(result2)
4)计算两个数组的并集
const result3 = [...new Set([...arr, ...arr2])] console.log(result3)//[1, 2, 5, 6, 4, 3, 7, 9]
11.2 Map
11.2.1初始化map对象
const map=new Map()
11.2.2添加元素set
map.set('name','张三') map.set('age',10) console.log(map)//Map { 'name' => '张三', 'age' => 10 }
11.2.3删除元素delete
const r=map.delete('name') console.log(r)//true console.log(map)//Map { 'age' => 10 }
11.2.4清空clear
map.clear() console.log(map)//Map { }
11.2.5遍历
for(let v of map){ console.log(v) }
11.2.6获取get
const map = new Map() map.set('name',111) console.log(map.get('name'))
存在时返回对应的值,不存在时返回undefined。
11.2.7 判断是否存在has
存在就返回true,不存在就返回false
const map = new Map() map.set('name',111) console.log(map.has('name'))
12.数值扩展
12.1 Number.isNaN()
console.log(Number.isNaN(123))
12.2 Number.parseInt()
把字符串转为整数。
1)如果字符串中以数字开头并包含字符,则只会截取字母前面的部分数字;如果字符串中不以数字开头,则返回NaN
2)如果字符串是一个浮点数,则只取整数部分,舍弃小数部分
console.log(Number.parseInt('125455'))//125455 console.log(Number.parseInt('12.9'))//12 console.log(Number.parseInt('-12.1'))//-12 console.log(Number.parseInt('0.12'))//0 console.log(Number.parseInt('-0.12'))//-0 console.log(Number.parseInt('1254pa20'))//1254 console.log(Number.parseInt('app'))//NaN console.log(Number.parseInt('aa325'))//NaN
12.3 Number.parseFloat()
把字符串转为浮点型数字。
1)如果字符串中以数字开头并包含字符,则只会截取字母前面的部分数字;如果字符串中不以数字开头,则返回NaN
2)如果小数部分是0,则只取整数部分,返回整数
console.log(Number.parseFloat('125455.0'))//125455 console.log(Number.parseFloat('12.9'))//12.9 console.log(Number.parseFloat('-12.1'))//-12.1 console.log(Number.parseFloat('1254.0pa20'))//1254 console.log(Number.parseFloat('app'))//NaN console.log(Number.parseFloat('aa325.0'))//NaN
12.4Number.isInteger()
console.log(Number.isInteger(0))//true console.log(Number.isInteger(125455.0))//true console.log(Number.isInteger(123))//true console.log(Number.isInteger(2.9))//false console.log(Number.isInteger(-12.1))//false
12.5 Math.trunc()
console.log(Math.trunc(2.9))//2 console.log(Math.trunc(2.1))//2
12.6 Math.sign()
console.log(Math.sign(20))//1 console.log(Math.sign(0))//0 console.log(Math.sign(-20))//-1
13.对象及对象方法的扩展
13.1对象字面量的增强写法
13.1.1对象属性的增强写法
//ES5写法 const name = "yuan"; const age = "21"; const sex = "man"; const obj = { name: name, age: age, sex: sex } //ES6写法 const name = "yuan"; const age = "21"; const sex = "man"; const obj = { name, age, sex }
13.1.2对象方法的增强写法
//ES5写法 const name = "yuan"; const obj = { getName: function(){ console.log("my name is " + name); } } //ES6写法 const name = "yuan"; const obj = { getName(){ console.log("my name is " + name); } }
13.2 Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。而Object.is()就可以解决这个问题。
console.log(Object.is('123','123'))//true console.log(Object.is('123','123.0'))//false console.log(Object.is(NaN,NaN))//true
13.3 Object.assign()
用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。第一个参数是目标对象,后面的参数都是源对象。它实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; //把source1,source2合并到target中 Object.assign(target, source1, source2) console.log(target)//{ a: 1, b: 2, c: 3 }
1)如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
//对象的合并Object.assign() const target = { a: 1, b: 5 }; const source1 = { b: 2, c: 6 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); console.log(target)//{ a: 1, b: 2, c: 3 }
Object.assign()
会直接返回该参数。
const obj = { a: 1 } console.log(Object.assign(obj) === obj)//true
3)如果该参数不是对象,则会先转成对象,然后返回。undefined
和null作为参数会报错,原因是他们无法转为对象。
console.log(typeof Object.assign(2))//object
4)如果非对象参数出现在源对象的位置,那么这些参数都会转成对象,如果无法转成对象,就会跳过。
let obj = {a: 1}; console.log(Object.assign(obj, undefined) === obj) // true console.log(Object.assign(obj, null) === obj) // true
5)其他类型的值(即数值、字符串和布尔值)不在首参数时,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
const v1 = 'abc'; const v2 = true; const v3 = 10; const obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
6)浅拷贝的实例
const obj1 = { a: { b: 1 } }; const obj2 = Object.assign({}, obj1); console.log(obj1.a.b)//1 console.log(obj1.a.b = 2) console.log(obj2.a.b) // 2
源对象obj1
的a
属性的值是一个对象,Object.assign()
拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面,上面的实例已经说明这个道理。
如果源对象中属性值不是对象,那么就只是拷贝这个值。那么就可以解决开发中的一些问题。例如vue中的数据复制地址问题,把一个对象先赋值给空对象,再对得到的对象进行修改,则不会影响源对象的内容。
// this.obj2=this.obj1//obj2的修改会直接影响obj1的值 this.obj2 = Object.assign({}, this.obj1)
因此可以使用第二行代码解决此问题。
13.4 Object.keys()
返回一个数组,成员是参数对象自身的所有可遍历属性的键名,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
var arr = ['a', 'b', 'c']; console.log(Object.keys(arr)); // ['0', '1', '2'] var obj = { 0: 'a', 3: 'b', 2: 'c' }; console.log(Object.keys(obj)); // ['0', '2', '3']
基于此功能,就可以获取对象中属性的个数
var obj = { 0: 'a', 3: 'b', 2: 'c' ,'name':'' }; console.log(Object.keys(obj).length); // 4
13.5 Object.values()
返回一个数组,成员是参数对象自身的所有可遍历属性的键值,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
var arr = ['a', 'b', 'c']; console.log(Object.values(arr)); //[ 'a', 'b', 'c' ] var obj = { 0: 'a', 3 :'b', 2: 'c' }; console.log(Object.values(obj)); //[ 'a', 'c', 'b' ]
13.6 Object.entries()
返回一个数组,成员是参数对象自身的所有可遍历属性的键值对数组。
var arr = ['a', 'b', 'c']; console.log(Object.entries(arr)); // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ] var obj = { 0: 'a', 3 :'b', 2: 'c' }; console.log(Object.entries(obj)); // [ [ '0', 'a' ], [ '2', 'c' ], [ '3', 'b' ] ]
13.7 Object.fromEntries()
是Object.entries()
的逆操作,用于将一个键值对数组转为对象。
console.log(Object.fromEntries([ [ '0', 'a' ], [ '2', 'c' ], [ '3', 'b' ] ]))//{ '0': 'a', '2': 'c', '3': 'b' }
14.数组的扩展
14.1 findIndex()
根据条件返回符合的数组的索引值,找不到返回-1。
let arrs = [1, 3, 5, 6, 4]
//获取值等于5的数组的索引,找不到就返回-1
let arr2 = arrs.findIndex(item => {
return item == 5
})
console.log(arr2 == -1 ? '未找到' : arr2)
14.2 Array.from()
用于将两类对象转为真正的数组。两类对象是类似数组的对象和可遍历的对象(部署了Iterator接口的数据结构)。
1)把类似数组的对象转为数组
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = Array.from(arrayLike); console.log(arr2)//[ 'a', 'b', 'c' ]
类似数组的对象中,不仅包含基本属性,还包含了长度。
2)把字符串转为数组
const arr3 = Array.from('hello') console.log(arr3)//[ 'h', 'e', 'l', 'l', 'o' ]
3)把set集合转为数组
let set=new Set() set.add(5) set.add(2) set.add(8) const arr4=Array.from(set) console.log(arr4)//[ 5, 2, 8 ]
14.3 Array.of()
将一组值,转换为数组。
console.log(Array.of(3, 11, 8)) // [3,11,8] console.log(Array.of(5)) // [5]
14.4 fill()
使用给定值,填充一个数组,数组中已有的元素,会被全部替换。。语法是fill(value,start,end),value是要填充的值(必选),start和end分别是要填充的起始和结束位置(可选)。
1)初始化空数组
const arr5 = new Array(3).fill(7) console.log(arr5)//[ 7, 7, 7 ]
2)全部替换数组内容
const arr6 = ['a', 'b', 'c'].fill(7) console.log(arr6)//[ 7, 7, 7 ]
3)部分替换
//从1号位开始,向原数组填充7,到2号位之前结束 const arr7 = ['a', 'b', 'c'].fill(7, 1, 2) console.log(arr7)//[ 'a', 7, 'c' ]
14.5 flat()
const arr = [4, 5, 8, [8, 9, 7, 6]] const newArr = arr.flat() console.log(newArr)//[ 4, 5, 8, 8, 9, 7, 6 ]
const arr2 = [4, 5, 8, [8, 9, 7, 6, 10, 51, [33, 52, 20]]] const newArr2 = arr2.flat() console.log(newArr2)//[ 4, 5, 8, 8, 9, 7, 6, 10, 51, [ 33, 52, 20 ] ]
3)把三维数组转为一维数组
const newArr3 = arr2.flat(2) console.log(newArr3)//[ 4, 5, 8, 8, 9, 7, 6, 10, 51, 33, 52, 20 ]
.