简介:ES6是JS的一种规范,也是JS的新特性
变量声明
1.let关键字
特性:
变量不能重复声明
1
2
3
4
5
6// 报错
let star = '123'
let star = '456'
// 不报错
var star = '123'
var star = '456'在该处的块级作用域才生效
在
if
,else
,while
,for
也是有相同的效果的1
2
3
4
5// 报错,但是使用var就不会报错
{
let star = "k"
}
console.log(star)不存在变量提升
不影响作用域链:函数内部还是可以访问到外部的变量的【可以闭包】
1
2
3
4
5
6let k = "asd"
function fn(){
console.log(k)
}
fn()
// output: asd
经典案例
1
2
3
4
5for(var i = 0; i < 3; i++){
items[i].onClick = function(){
items[i].style.background = 'pink'
}
}上面的代码就会导致错误,因为在上面,i是全局的,然后在监听触发的时候,i就已经无视代码块变成了3,接着在里面找不到items[3]导致报错
因此需要将var变成let,这样的话,i就不会污染三个块级区域了。
1
2
3
4
5
6
7
8
9
10
11
12
13for(let i = 0; i < items.length; i++){
items[i].onClick = function(){
items[i].style.background = 'pink'
}
}
// ----------这也是其中一种方法,用this来确定i------------- //
for(var i = 0; i < items.length; i++){
items[i].onClick = function(){
this.style.background = 'pink'
}
}
2.const关键字
作用:用于声明常量
注意事项:
一定要赋初始值,不然报错
一般常量使用大写
常量的值不能修改
它也用于块级作用域
对于数组和对象的元素修改,不算作对常量的修改,不会报错
1
2
3
4
5
6// 不会报错
const TEAM = ['UZI', 'AUG']
TEAM.push('XM8')
// 会报错
TEAM = 100原因:常量值虽然发生了变化【指增加删减元素】,但是常量的栈地址没有发生变化,只变了堆内存地址,因此不会报错
解构赋值
- ES6允许按照一定模式从数组对象中来提取值,对变量进行赋值
1.数组的结构赋值
1 | const F = ['UZI', 'AUG', 'XM8'] |
我们发现都是自己根据位置来赋值的
2.对象的解构
1 | const p = { |
我们发现与数组类似,都是直接取出,如果不打算全部取的话,就必须按照属性原名取出即可
模板字符串
1.声明方式
1 | let str = `I_am_a_string` |
2.与普通字符串的区别
内容中可以出现换行符
1
2
3
4
5
6
7
8
9// 错误的,只能通过加法拼接,并且还没有换行符
let str = "<ul>
<li>example</li>
</ul>"
// 模板字符串
let str = `<ul>
<li>example</li>
</ul>`可以拼接变量
1
2
3let exp = "示例"
let out = `${exp}显示成功`
// output:示例显示成功
对象写法
在ES6里面允许在大括号直接写入变量和函数【类似于vue】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16let name = 'lkd'
let change = function(){
console.log('lkd')
}
// 这就是ES6的简化写法,类似于vue中引入组件一样
// 在这里也可以用下面直接声明的方法【以ins为例】
const object = {
name,
change,
// 这个地方等价于:
// ins: function(){}
ins(){
console.log('即时创建简化声明的方法')
}
}
函数相关
1.箭头函数
特性
this是静态的,this始终是指向函数声明时所在作用域下的this的值
call方法是可以用来改变作用域的,但是箭头函数是静态的,this不会遭到变动,因此使用call方法是不会发生变化的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function getName(){
console.log(this.name)
}
let getName2 = () => {
console.log(this.name)
}
window.name = "lkd"
const obj = {
name: "obj"
}
// 输出lkd,lkd
getName()
getName2()
// 输出obj,lkd
getName.call(obj)
getName2.call(obj)因此不能作为构造函数实例化对象,否则报错
1
2
3
4
5
6
7// 报错,不能产生实例化对象
let person = (name, age) => {
this.name = name
this.age = age
}
let m = new person("123",123)
console.log(m)
不能使用arguments变量
1 | // 报错,因为已经没有arguments对象了 |
简写方法
只有一个参数时,省略小括号
1
2
3let fn = n => {
console.log(n)
}只有一个return语句时,省略花括号和return
1
let fn = (m, n) => m * n
2.参数相关
默认值
我们可以给函数添加默认值,但是有默认值的必须放到最后
1
2
3
4
5
6const p = (a, b, c = 10) => {
return a + b + c
}
// output: 23
// 在这里因为没有传入c,因此c传入默认值10
p(1, 2)一定程度上可以和解构赋值结合书写
1
2
3
4
5
6
7
8
9
10
11
12
13const p = ({host, username, password, port}) => {
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
// output: 127.0.0.1, root, root, 3306
p({
host: 127.0.0.1,
username: root,
password: root,
port: 3306
})
rest参数
在ES6废弃了arguments之后,我们使用rest参数来获取函数的参数变量
就是将变量当作是数组传入,然后再解出来
1
2
3
4
5const p = (...args) => {
console.log(args)
}
// output: [1, 2, 3, 4, 5, 6]
p(1, 2, 3, 4, 5, 6)与argument不同的是,rest参数是数组存储,更具灵活性;而arguments使用对象存储
rest参数必须放到最后,不然会报错
1
2
3
4
5
6
7const p = (a, b, ...args) => {
console.log(a)
console.log(b)
console.log(args)
}
// output: 1, 2, [3, 4, 5]
p(1, 2, 3, 4, 5)
扩展运算符
1.扩展运算符的定义与作用
符号:
...
...
可以将数组拆出1
2
3
4
5
6const arr = [1, 2, 3, 4, 5]
const fn = (arr) => {
console.log(...arr)
}
// output: 1 2 3 4 5
fn(arr)
2.扩展运算符应用
合并数组
1
2
3
4
5var arr1 = [1, 2, 3]
var arr2 = ['UZI', 'AUG', 'XM8']
var arrFinal = [...arr1, ...arr2]
// output: 1 2 3 'UZI' 'AUG' 'XM8'
console.log(arrFinal)当然,我们也可以使用concat来实现
1
2
3
4
5var arr1 = [1, 2, 3]
var arr2 = ['UZI', 'AUG', 'XM8']
var arrFinal = arr1.concat(arr2)
// output: 1 2 3 'UZI' 'AUG' 'XM8'
console.log(arrFinal)克隆数组
1
2var arr1 = [1, 2, 3]
var arr2 = [...arr1]转换伪数组
HTML文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
<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></div>
<div></div>
<div></div>
</body>
</html>js文件:
1
2
3
4
5
6
7const divs = document.querySelectorAll('div')
// output: [div, div, div]
// 虽然是数组,但是是有原型对象的,为ListNode,是伪数组
console.log(divs)
const divArr = [...divs]
// 这样就是数组了,有数组的方法
console.log(divArr)
Symbol
1.定义
Symbol是ES6的一种新的数据类型,类似于字符串的数据类型
Symbol表示独一无二的值,就算是两个变量的数值相同,在判定的时候也会被判为false
2.共享体系
Symbol也有for方法来创建对象,可以作为一个共享体系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let s = Symbol()
// output: Symbol() 'symbol'
console.log(s, typeof(s))
// ---------------------------- //
let s2 = Symbol('lkd')
let s3 = Symbol('lkd')
// output: false
console.log(s2 === s3)
// ---------------------------- //
let s4 = Symbol.for('lkd')
let s5 = Symbol.for('lkd')
// output: true
console.log(s4 === s5)我们可以使用Symbol.keyFor()方法在Symbol全局注册表中检索是否有该键对应值
1
2
3
4
5
6let k1 = Symbol.for('k1')
let k2 = Symbol('k2')
// output: k1 undefined
console.log(Symbol.keyFor(k1))
console.log(Symbol.keyFor(k2))
3.特点
不能和其他数据进行运算
1
2// 报错
let result = s4 + '100'唯一性极高
4.使用方法
给对象添加独一无二的属性和方法
比如,我想给obj添加属性,但是不确定该属性有没有,就可以使用symbol了。
1
2
3
4
5
6
7
8
9
10
11
12let game = {}
let methods = {
up: Symbol(),
down: Symbol()
}
game[methods.up] = function(){
console.log("up")
}
game[methods.down] = function(){
console.log("down")
}
console.log(game)当然,我也可以直接在对象内部添加方法
1
2
3
4
5let game = {
[Symbol('say')]: function(){
console.log("say")
}
}
5.Symbol内置值
Symbol.hasInstance:当其他对象使用instanceof运算符,判断是否为该对象的实例时就会使用这个方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Person {
static [Symbol.hasInstance](param){
console.log(param)
console.log("lkd")
}
}
let o = {}
// output: {}
// lkd
// false
console.log(o instanceof Person)
// output: false
console.log(Person[Symbol.hasInstance](o))为什么不只用instanceof方便呢?因为在这里我们可以随便改变instanceof的运行方式
1
2
3
4
5
6
7
8
9class Person {
static [Symbol.hasInstance](param){
return false
}
}
let o = new Person()
// output: false
// 在这里本来是true才是正常的,但是我们硬编码了实例对象的判定方法
console.log(o instanceof Person)Symbol.isConcatSpreadable:布尔值,用于表示是否将集合内元素归类到一个层级
数组拼接的时候都会将数组展开成零散的数
也就是说,该值是为了判断是否展开该层级
1
2
3
4
5
6
7const arr = [1, 2, 3]
const arr2 = [4, 5, 6]
// output: [1, 2, 3, 4, 5, 6]
console.log(arr.concat(arr2))
arr2[Symbol.isConcatSpreadable] = false
// output: [1, 2, 3, [4, 5, 6]]
console.log(arr.concat(arr2))
迭代器
1.作用
- 用于为各种不同的数据结构提供统一的访问机制
- 使得数据结构成员能够按某种次序排列
- ES6创造了一个新的遍历命令for-of循环
- 迭代强调依次取出
2.工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针一直向后移动,只得到指向最后一个成员
- 每调用next方法返回一个包含value和done属性的对象
1 | const arr = ['AUG', 'XM8', 'UZI'] |
3.自定义遍历数据
- [Symbol.iterator]:迭代方法,可以内置于对象中,作为for-of的迭代方式
- 可以自定义遍历哪个属性的对象
- 可以自定义遍历顺序
- next方法:用于规定循环的下一个对象是谁,通常是一个有着value和done的对象,通常是一个函数
- value:定义下一个指针的指向
- done:定义是否再进行一次指向
1 | const _class = { |
4.新增的数据结构
集合
Set():集合,里面的数都有着不重复的特性
注意,要用let来定义
1
2let set = new Set([1, 2, 3, 3, 4, 4])
console.log(set)方法主要为:
has(x):用于判断值x是否存在于集合中
add(x):添加元素x
delete(x):删除元素x
clear():删除所有元素
size():返回集合长度
我们一般转回数组都是使用Array.from(set)来将集合转换为数组,当然from方法就是用来转换数据结构的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var arr = [1, 2, 2, 3, 4, 5]
let set = new Set(arr)
// output: false
console.log(set.has(6))
// set[1, 2, 3, 4, 5, 6]
set.add(6)
console.log(set)
// set[2, 3, 4, 5, 6]
set.delete(1)
console.log(set)
// 5
console.log(set.size)
var arr2 = Array.from(set)
// array[2, 3, 4, 5, 6]
console.log(arr2)
上面的方法是链式的
1
2
3
4
5
6
7
8let set = new Set()
let a = NaN
let b = NaN
let c = {}
let d = {}
// 记住,两个对象的栈地址不相同,那么他们也就不相同
// [NaN, {}, {}]
set.add(a).add(b).add(c).add(d)
映射
Map():映射,里面存的是键值对,当然比对象更加好,因为可以使用任意值作为键值
当然,里面的键值对也有不重复的特性
1 | const map = new Map([[1, 2], [3, 4], [1, 2]]) |
方法主要为:
set(x, y):添加键值对(x ,y)
get(x):得到键值为x的另一边
clear():清空所有键值对
1
2
3
4
5
6
7
8
9const map = new Map([[1, 2], [3, 4], [1, 2]])
// 2
console.log(map.get(1))
map.set("string1", "string2")
// 3
console.log(map.size)
map.clear()
// 0
console.log(map.size)
生成器
1.定义
- 生成器是一种ES6独有的异步函数
2.创建方法
- 使用
*
来创建 - yield用来分割函数内部作用域
- next方法用于向下执行作用域
- 这种函数只能通过next向下执行,否则就会在yield处被切断
1 | function * gen(){ |
3.生成器的参数传递
()括号内部的可以正常传递
1
2
3
4
5
6
7function * gen(len){
console.log(len)
yield '-----------'
}
let iterator = gen('123')
// output: '123'
iterator.next()next传进来的值会改变yield后面的值
注意:只能改变下一个yield的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function * gen(len){
console.log(len)
yield '-----------'
console.log(1)
yield '-----------'
console.log(2)
const one = yield '-----------'
console.log(one)
}
let iterator = gen('123')
iterator.next('456')
iterator.next()
iterator.next()
iterator.next('789')
// output:
// '123'
// 1
// 2
// '789'
4.异步使用的实例
- 解除回调地狱
1 | // 1s - 2s - 4s 依次打印 |
- 拿出函数内部数据
1 | let one = () => { |
Promise
1.定义
- Promise是ES6引入的异步编程的新解决方案
- 语法上来说它是一个构造函数,用来封装异步操作并可以获取其成功或者失败的结果
2.基本使用
1 | const p = new Promise(function(resolve, reject){ |
3.Promise封装读取文件
- 读取单个文件
1 | var fs = require('fs') |
- 次序读取多个文件
1 | var fs = require('fs') |
4.Promise封装Ajax请求
简易请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 创建对象
const xhr = new XMLHttpRequest()
// 初始化
xhr.open("GET", "https://127.0.0.1:3000/server")
// 发送请求
xhr.send()
// 绑定事件,处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response)
}else{
console.log(xhr.status)
}
}
}封装请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const p = new Promise((resolve, reject) => {
// 创建对象
const xhr = new XMLHttpRequest()
// 初始化
xhr.open("GET", "https://127.0.0.1:3000/server")
// 发送请求
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)
}, (reject) => {
console.err(reject)
})
ES7新特性
数组添加includes方法
1
2const arr = ['AUG', 'XM8', 'UZI']
arr.includes('AWM') // false幂的计算
1
var a = 2 ** 3 // 9
ES8新特性
1.async和await
- async和await两者可以使异步代码像同步代码执行
async
- async函数的返回值为promise对象
- promise对象的结果由async函数执行的返回值决定
1 | async function fn(){ |
await
- await必须写在async函数中【单项依赖】
- await右侧的表达式一般为promise对象
- await返回的是promise成功的值
- await的promise失败了就会抛出异常,需要用try-catch捕获处理
1 | const p = new Promise((resolve, reject) => { |
2.借助async和await依次读取文件
借用读取文件的异步,来等价替换为其他的异步也是可行的
1 | const fs = require('fs') |
3.async和await封装Ajax请求
1 | function sendAjax(url){ |
ES9新特性
1.对象的拓展运算符和rest
...
运算符可以对对象使用了,这样就是拆出一系列的键值对,当然也可以用来合上1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var skill1 = {
Q: '斩钢闪',
W: '风之障壁'
}
var skill2 = {
E: '踏前斩'
}
var skill3 = {
R: '狂风绝息斩',
passive: '浪客之道'
}
var skill = {
...skill1,
...skill2,
...skill3
}
console.log(skill)拓展运算符也可以用在对象的属性里面了,这样子传入的对象就可以是属性不确定了
1
2
3
4
5
6
7
8
9
10
11
12
13function connect({host, port, ...user}){
console.log(host)
console.log(port)
console.log(user)
}
// output: '127.0.0.1' 3306 {username: 'root', password: 'root'}
connect({
host: '127.0.0.1',
port: 3306,
username: 'root',
password: 'root'
})
2.正则扩展
命名捕获分组
- 注意,正则得到的结果里面有一个groups的对象属性,不对正则到的字符贴标签就为undefined
1 | let str = '<a href="http://www.baidu.com">百度</a>' |
1 | let str = '<a href="http://www.baidu.com">百度</a>' |
断言
断言:判断匹配结果是否正确的规则
正向断言:根据后面的内容来判断取出字符
1
2
3
4
5let str = "123123123456qwe123"
const reg = /\d+(?=qwe)/
// output: 123123123456
const result = reg.exec(str)反向断言:根据前面的内容来判断取出字符
1
2
3
4let str = "123123123456qwe123"
const reg = /(?<=qwe)\d+/
// output: 123
const result = reg.exec(str)
dot-All模式
.
:代表除了换行符之外的任何一个字符我们在正则表达式的后面加上gs,进行带换行符的全局匹配
- 换行符用
.*?
来表示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16let str =
`<ul>
<li>电影1</li>
<p>时间1</p>
</ul>`
// /s 换行 g代表global
// 常规模式匹配:需要将换行符考虑进去
//const reg = /<ul>\s+<li>(.*?)<\/li>\s+<p>(.*?)<\/p>\s+<\/ul>/
// dot-All模式:可以将换行符给替换掉为*?
const reg = /<ul>.*?<li>(.*?)<\/li>.*?<p>(.*?)<\/p>.*?<\/ul>/gs
let result
let data = []
while(result = reg.exec(str)){
data.push({title: result[1], time: result[2]})
}
console.log(data)- 换行符用
ES10新特性
1.对象拓展方法
Object.fromEntries:用于创建对象,接收二维数组或者Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 二维数组
const result = Object.fromEntries([
['name', 'lkd'],
['age', 30],
['grade', 3],
['class', 2]
])
// {name: 'lkd', age: 30, grade: 2, class: 3}
console.log(result)
// 使用Map也是同样的道理
const map_ = new Map()
map_.set('name', 'lkd')
const result2 = Object.fromEntries(map_)
// {name: 'lkd'}
console.log(result2)在ES8中,有将对象转换为二维数组的:
Object.entries
1
2
3
4var arr = Object.entries({
name: 'lkd'
})
console.log(arr)
2.字符串扩展方法
trimStart:清除左侧的字符
trimEnd:清除右侧的字符
trim:清除左右两侧的字符
1
2
3
4
5
6
7let str = ` lkd lkd `
// `lkd lkd`
console.log(str.trim())
// `lkd lkd `
console.log(str.trimStart())
// ` lkd lkd`
console.log(str.trimEnd())
3.数组方法扩展
flat(x)
:将多为数组转化为低位数组,x表示转化深度1
2
3
4
5
6
7
8
9
10
11const arr = [1, 2, 3, 4, [5, 6]]
// [1, 2, 3, 4, 5, 6]
console.log(arr.flat())
// 三维数组的深度为2
const arr2 = [1, 2, [3, 4, [5, 6]]]
// [1, 2, 3, 4, [5, 6]]
console.log(arr2.flat())
// [1, 2, 3, 4, 5, 6]
console.log(arr2.flat(2))flatMap(x)
:改进map方法,使数组变成一维数组1
2
3
4
5const arr = [1, 2, 3]
// 虽然操作之后的每一个返回值是数组,但是还是将其变成了低位数组
const result = arr.flatMap(item => [item * 10])
// [10, 20, 30]
console.log(result)