ES6

什么是ES6?

来自: https://www.dengruicode.com/classes?uuid=04682448c47b45e980e57d476918d740

ES6实际上叫做ECMAScript

ECMA指的是一种规范,所以ECMAScript指的是遵从这个规范的脚本语言

所以这个实际上是一个规范

可以说ES6是一本目录,而javascipt是实现的具体内容

而之所以说是ES6实际上是因为ES6是一次重大的版本更新,实际上从ES6-ES13都被叫做ES6

一些规范

变量和常量

变量就是一个符号,代表了一些不确定的值

常量就是一个符号,代表了确定的一个值

为什么要弄一个常量出来呢?

因为变量的效率不如常量,而且常量的一个功能就是减少编程量,以及统一修改

变量

定义变量

通过let关键字来声明一个变量

1
let varable = "一个变量"

常量

定义常量

通过const关键字来声明一个常量并给起赋值

1
const PI = 3.1415

数据类型

在叫脚本语言中,常用的并不是系统级的开发,所以脚本语言往往将常用的类型保留出来,而不是像java一样将所有的类型尽量同一成类

一共有7中数据类型

注意这里说的数据类型,中的数据是核心意义,

比如对象,是用来保存数据的类型

而类class也是要来保存数据的

简单类型

字符串string

数值类型number

布尔类型boolean

集合类型

对象object 实际上更像是一种Map

对象

检测到{}包裹那么这个值会被考虑为对象

有一种简写形式,如果只写了值,那么这个值的键就是值标识符的字符串,例如{student},那么相当于{‘student’:student}

let student = {

​ name:”yanion”,

​ age:14,

​ gender:”男”

}

对象可以携带其他类型的数据

键值对map

map实际上和对象很像,所以他们的区别是什么呢?

提供了更加灵活的键值对存储和操作方式get,set,entires,foreach,keys,values,delete

需要通过new 关键字操作

1
let myMap = new Map([["name","Lua"],["age",18]])

如果使用typeof关键字输出这个类型的值的话,得到的显示也是object,这是因为分的不是那么详细

在语法上:
map通过中括号囊括的键值对,因为每个键值对都是同样的结果

​ 也是通过中括号表示一个键值对,键值对的第一个元素作为键,第二个元素作为值

​ 键和值两个类型可以任意

数组array

数组

一种有序,可以包含不同类型的元素(这里是ECMAscript中的定义,在其他语言中要求是一种类型)

长度是可变的

定义

1
let arr = [1,"2",true]

也是通过中括号表示数组

集合 set

set集合元素不重复,顺序不固定

1
let myset = new set([1,2,3,2,1])

定义类型

函数 function

function

一种可以重复执行的代码块,可以接收参数并返回一个值或者执行某些操作

(代码不仅仅可以操作传入的参数,还可以操作当前context上下文中的参数),实际上就是栈下面的那些

定义函数

1
2
3
4
5
function add(x,y){
return x+y
}
//调用函数
console.log(add(10,20))

类 class

这个是es6新引入的概念

类是一种蓝图或者模版,用于创建具有相同结构的对象,所以object是结果,而属于某种类的对象是更严格的要求

定义类

1
2
3
4
5
6
7
8
9
10
11
12
class Person{
name
age
constructor(name,age){
this.name = name
this.age = age
//即使我们没有显式的定义属性,但是只要我们操作了这个属性就会自动创建
}
info(){
console.log("name:"+name+",age:"+age)
}
}

具体的讲解

函数

这里的函数不同于java中的方法

es6中的函数是一个对象,可以被传递到不同的变量中

定义使用function关键字

返回值使用return

设置默认值function add(x = 10,y = 20){…}

匿名函数

匿名函数和普通函数的区别就是 普通函数有一个唯一的常量符号与之对应,可以始终通过这个符号调用函数

而匿名函数没有唯一的对应符号,如果匿名函数没有被任何变量存储,那么他就真的不存在了

1
2
3
4
let sub = function(x,y){
return x - y
}
//如果我们将sub覆盖,那么这个函数就无法找到了

匿名函数通常被用作回调函数,这种函数不会到处执行,通常之执行一次

箭头函数

箭头函数实际上也是一种匿名函数

1
2
3
let  plus = (a,b)=>{
return a+b
}

箭头函数可以省略函数的语法,最直接的就是不用写function关键字了

还可以隐式返回,就是当返回值是一个表达式的时候可以直接省略returrn关键字和函数体花括号

1
let plus = (a,b)=>a+b

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义数组
let arr - [1,2,3]
//添加元素,并返回新的长度
arr.push(1,2,3)
//shift删除第一个元素,并返回被删除的元素
//unshift从头添加新的元素,并返回新的长度
//pop删除最后一个元素,并返回被删除的元素
//删除一块的元素splice(beginindex, length),并返回被删除的数组
//reverse方法颠倒元素的顺序
//sort方法,按照元素的字符串字典序升序排序
//sort方法的参数可以给一个比较函数,从而比较各种类型的元素(a,b)=>a-b
//筛选符合条件的元素filter((value,index)=>value>12)
//concat方法连接两个数组.concat(新的数组,插入位置)
//for循环数组
//foreach方法遍历 .foreach(value => console.log(value+","))

Set集合

创建set集合

let myset = new set([“apple”,”banana”])

添加元素

myset.add(“fruit”)

删除元素

myset,delete(“banana”)

判断元素是不是在集合中

myset.has(“banana”)

获取集合的大小

myyset.size

转换为数组

let arr = Array.from(myset)

扩展运算符

扩展运算符作用于任何由多个同等部分组成的对象

例如字符串是由字符组合而成的,而set也是

扩展运算符的结果是内容使用逗号分隔

1
2
3
let string = "123"
let arr = [...string]
//得到的就是["1","2","3"]

可以使用for遍历

也可以使用foreach方法,但是传入的参数value=>{}注意array的foreach方法多了一个index参数

那是因为集合中没有顺序,所以元素没有index,只能是自身的元素表示自身

使用set将数组去重

let arr = [1,2,134,123,12,2,1,111,1]

let numset = new set(arr)

arr = Array.from(numset)

遍历元素

for(let e of set)

Map集合

创建Map

let mymap = new Map([

[“name”,”nama”],[“age”,13]

])

添加,或者更新键值对

mymap.set(“key”,”value)

删除某个键

mymap.delete(“age”)

判断是否包含

mymap.has(“age”)

获取map集合的大小

mymap.size

将map转换为数组

使用Array.from或者扩展运算符都可以

遍历map集合

使用for(let [key,value] of mymap)或者foreach((value,key)=>{})都可以

删除所有的元素

clear()

对象object

let student = {

age:12,

name:”uyanion”

}

修改和读取属性

student.name = “new name”

let name = student.name

删除属性

delete student.age

判断是否包含某个属性

使用in关键字 let has = “name” in student

获取所有属性结构

Object.keys(student)

获取对象属性的个数

只能使用keys().length获取到数组再获取数组的元素

for遍历对象的属性

这里还是用到了in关键字,和map和set的of关键字不同

for(let key in student)

或者使用foreach

Object.enties(student).foreach(([key,value]=>{}))

可以发现相比于map和set,这个object的操作非常困难

清空对象

直接student = {}

对象转Map

1
2
3
let plainObject = { "one": 1, "two": 2, "three": 3 };
let map = new Map(Object.entries(plainObject));
console.log(map);

类的私有属性

指的是仅仅可以在类的内部直接访问的属性

1
2
3
4
5
6
7
8
9
10
class person{
name
age
constructor(name,age){
this.name=name
this.age=age
}

}

使用#开头的属性就是私有属性

1
2
3
4
5
6
7
8
9
10
11
class person{
#name
age
constructor(name,age){
this.#name=name
this.age=age
}

}
//error person.name

相应的在内部我们使用这个属性也需要加上#,此时外部不知道是#所以不会写#

如果想要外部直接访问的方式可以获取到值

通过一个get关键字声明

了一个方法是一个get方法,这个方法的函数名就是外部看到的属性名,可以修改成别的,所以实际上访问的是函数而不是直接访问的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
class person{
#name
age
constructor(name,age){
this.#name=name
this.age=age
}
get name(){
return this.#name
}

}
// noerror person.name

通过set关键子声明一个赋值方法

1
2
3
4
//通过set关键字重载赋值
set name(value){
this.#name = value
}

模板字符串

使用反引号的方法引起来的字符串,会先经过解析在变成字符串

1
return `name:${this.#name},age:${this.age}`

就和EL表达式一样

类的继承

和java一样,使用extends关键字

另外super关键字可以调用父类例如super()就是父类的构造函数

解构

也就是将一些拥有结构的数据提取出来,扁平化

例如

1
let [x,y] = [1,2]

这里将数组中的两个元素解构到了变量x和y中

1
2
let [,,c] = [1,2,3]
//这里,号起到站位作用,表示将第三个元素解构到c

使用扩展运算符

1
2
let [a,...b] = [1,23,4,45,5]
//这样得到的是a=1,b=[23,4,45,5]

如果解构无法满足

一些元素会被赋值为undefined

我们可以提前设置默认值来避免种种情况

1
let [x,y=200] = [100]

解构用来两数交换

1
2
3
let x = 20
let y = 30; //这里必须加分号,因为 下面的表达式
[x,y] = [y,x]

对象的解构

1
2
3
let {name} = person //person = {name:"yanion",age:13}
console.log(name)
//这个时候就可以console.log(name)发现就是yanion

我们知道这个name对应的就是person对象中的name属性名

但是如果还想要取得name怎么办呢?已经有一个name变量了

所以要用到

块作用域重命名

1
2
3
let {name:username, age} = person
//相当于说将name属性复制到username变量
console.log(username)

这样就创建的username,而不是name了

Promise

含义是承诺,事实上和java中的异步CompletedFuture类似

表示承诺在未来可能会未完成并返回一个结果

三个状态

  1. 待处理pending
  2. 已履行fulfilled
  3. 已驳回rejected

如何使用promise

1
2
3
4
5
6
let promise = new promise((resolve,reject)=>{
...一系列,需要花时间的代码...
resolve("我完成了")//完成了就调用resolve方法来告诉外界,未完成的事实,此时promise对象会从pending状态转到fulfilled
reject("没有完成,失败了")//或者出现了问题,失败了

})

我们可以继续设置,当promise进入fulfilled状态之后的处理流程

1
2
3
4
5
6
7
8
9
promise.then(result => {
console.log(result)
}).catch(error = >{
console.log(result)
}).finally(()=>{
console.log("无论是resolve还是reject,当异步执行结束时都会走这个过程处理")
})
//这里的result就是在promise内部的resolve方法传入的参数,而then就是外部知道promise完成之后所执行的后续操作
//而catch就是对reject也就是rejected状态的后续处理方法,error是内部reject方法的传入参数

Fetch

这个真的和ajax的方法有点类似

fetch可以发送异步请求

例如发送get请求

1
2
3
4
5
6
7
8
9
fetch("url").then(response=>{
return response.json()//将响应数据通过json转换成对象,返回给后面的处理
}).then(data => {
//处理数据
}).catch(error=>{
//如果响应出现问题就会调用这个而不是then
}).finally(()=>{
//无论如何会调用这个finally
})

发送post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fetch("url",{
method:"post",//这里就是加载http请求的head上面
headers:{
'content-type':"application/x-wwww-form-urlencoded"//这个请求头表示参数类型是表单
},
body: new URLSearchParams({
//urlsearchparams 用于处理键值对数据类型,并将器编码为url查询字符串
name:"yanion",
age:12
}),
}).then(respnonse => {
return response.json()
}).then(data => {

}).catch(error=>{

}).finally(()=>{

})

可以看到,最大的区别就是fetch的第二个参数变成了一个对象

对象中需要提供method,headers,body等属性

发送Json参数

表单参数的作用有限,没法传输更多的复杂数据

而json就可以传输一个结构数据,保留了数据的结构

改变的关键就是headers中的content-type字段值,以及在body中的是json字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fetch("url",{
method:"POST",
headers:{
'COntent-type':"application/json"
},
body: JSON.stringify({
//JSON.stringify方法用于将对象转换为json字符串
name:"yanion",
age:12,
}),
}).then(response=>{
return response.json()
}).then(data=>{

}).catch(error=>{

}).finally(()=>{

})

node.js和重要的第三方库

node.js详细看node.js的学习文档,这里提供node.js的更改镜像的方法

1
2
3
4
# 查看镜像源
npm get registry
# 设置淘宝镜像源
npm config set registry https://registry.npmmirror.com/

axios网络请求库

这个是一个很知名的网络请求库,基于promise的异步请求库

安装axios库

通过npm可以快速的安装axios的所有模块

1
npm install axios

根据CDN内容分发网,找到核心文件

image-20240616111859934

我们可以看到么新文件axios.min.js在axios目录下的dist目录,我们就可以引用这个文件

什么是axios?

axios是基于promise的网络请求库,发送http请求并响应服务端发送的数据

可以发现,axios的作用和fetch差不多,他们之间有什么区别呢

  1. fetch是基于浏览器的原生api,所以fetch只能用于浏览器,实际上是浏览器的api
  2. axios依赖于第三方库文件(axiosmin.js),不仅可以=用于浏览器也可以用于node.js环境

发送get请求

1
2
3
4
5
6
7
8
9
//get请求
axios.get('http://127.0.0.1/get').then(response => {
console.log("get.data:", response.data)
}).catch(error => {
console.log("get.error:", error)
}).finally(() => {
console.log("get.finally")
})

  1. 可发现,通过调用get方法直接就可以了,而fetch中的方法需要通过第二个参数对象中的method设置(虽然fetch默认就是get)

  2. 不用使用return response.json(),直接使用response.data来获取响应数据

post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//post请求 post
let data = { //参数
name: '邓瑞',
web: 'dengruicode.com',
}

axios.post('http://127.0.0.1/post', data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(response => {
console.log("post.data:", response.data)
}).catch(error => {
console.log("post.error:", error)
}).finally(() => {
console.log("post.finally")
})

可以发现,axios比较聪明,知道post请求中的请求参数比较重要,所以直接将第二个参数给到了请求数据对象,

使用post方法有三个参数

使用post请求传递json数据

直接不用写headers了,因为axios的post方法默认headers就是application/json

我们直接传入data作为post的第二个参数即可,会自动转话为json字符串

1
2
3
4
5
6
7
8
//post请求 postJson [axios 的默认请求头是 application/json]
axios.post('http://127.0.0.1/postJson', data).then(response => {
console.log("postJson.data:", response.data)
}).catch(error => {
console.log("postJson.error:", error)
}).finally(() => {
console.log("postJson.finally")
})

模块化开发

模块化开发指的是将复杂代码开分成独立模块,每个模块负责开发特定功能

不同的模块直接通过export关键字,可以导出模块,其他模块可以使用import关键字导入该模块

模块化的另一个好处是,可以定义为别名,这样可以避免命名冲突

  1. 防止命名冲突
  2. 代码复用
  3. 高维护性

要实现这个功能,需要解决的问题有如何唯一定位,如何统合建立联系

功能主要由export 和 import两个关键字支持

export规定模块的对外接口

import规定了引入哪些接口

export关键字

实际上这个关键字可以加在任意的标识符上,这样就将标识符暴露在外部.

1
2
3
4
5
export let myname = "Li hua"
export function teacher(){
return 'zhang fei'
}
//分别标注暴露

但是这样就有很多的工作量,要写很多的export

我们还可以这样用

1
2
3
4
5
6
7
let myname = 123
function teacher(){
return 456
}

export {myname, teacher}
//统一写暴露标识符

还可以默认暴露

1
2
3
4
5
6
7
8
export default {
myname : 123,
teacher: function(){
return 456
}
}
export default student
//可以看出,默认暴露实际上就是不用再套一层{}对象的壳子,如果只要一个对象导出

import关键字

第一种通用导入方式,如果在html中要导入模块一定要加上type=module

1
2
3
4
5
<script type="module" >
//引入模块
import * as m1 from "文件.js"
//这样的意思就是将暴露出来的接口放到m1命名空间里边,这样我们就可以使用m1.之前的标识符来访问原来的标识符
</script>

解构赋值方式

1
2
import {school,teach} from "文件.js"
//这样就可以直接使用school和teach两个标识符了

起别名

1
import {school as smallSchool, teach as tea} from "文件,js"

对默认暴露的default对象起别名

1
import {default as myName} from "文件.js"

只能针对默认暴露的简便导入方式

1
2
import 属性名 from "文件.js"
//因为默认暴露是对象所以才可以这样做

动态导入

ES2020提案 引入import()函数,支持动态加载模块。

之前的import是静态导入的

旧的初次学习笔记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
------ importexport
//index.js
let title = "邓瑞编程"
let web = "dengruicode.com"

/*
let getWeb = () => {
return "www.dengruicode.com"
}
*/
let getWeb = () => "www.dengruicode.com"

export { title, web, getWeb } //将多个变量或函数分别导出

<script type="module">
//从 index.js 文件中导入 title、web、getWeb 变量/函数
import { title as webTitle, web, getWeb } from './index.js'

console.log(webTitle)
console.log(web)
console.log(getWeb())
</script>

------ default
//index.js
let title = "邓瑞编程"
let web = "dengruicode.com"

let getWeb = () => "www.dengruicode.com"

//将一个对象作为整体导出, 导出的对象包含 title、web、getWeb 三个属性
export default { title, web, getWeb }

<script type="module">
import obj from "./index.js"

console.log(obj.title)
console.log(obj.web)
console.log(obj.getWeb())
</script>
------ as
//index.js
let title = "邓瑞编程"
let web = "dengruicode.com"
let getWeb = () => "www.dengruicode.com"
export { title, web, getWeb } //将多个变量或函数分别导出

<script type="module">
import * as obj from "./index.js"

console.log(obj.title)
console.log(obj.web)
console.log(obj.getWeb())
</script>

实际上导出是导出一个对象obj所以要是使用一个大括号

export {title,web}

在导入的时候可以使用解构的语法

import {title as webtitle , web} from ‘index.js’

也可以直接接受为一个对象

import * as obj from ‘index.js’

或者

export default {title, web} //当使用default的时候默认导出的是一个对象,所以就可以直接接受

import obj from ‘index.js’

当import的是一个对象

我们就可以使用obj.title使用.来访问

异步async和同步await

async和await是两个关键字,用于修饰函数

async

当一个函数被标记为 async 后, 该函数会返回一个 Promise 对象

用在函数的定义阶段,这样的函数的返回结果会被包装到一个promise对象中

例如

1
2
3
const  getData = async ()=>{

}

await

只能在 async 函数内部使用, 加上 await 关键字后, 会在执行到这一行时暂停函数的剩余部分,

等待网络请求完成,然后继续执行并获取到请求返回的数据

作用与async函数内部的请求方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//async/await 使用同步的方式编写异步代码, 避免回调地狱
//优势 在处理多个异步操作的情况下, 可以使代码更简洁易读
const getData = async () => {
try {
//get请求
const response = await axios.get('http://127.0.0.1/get')
console.log("async.get.data:", response.data)
if (response.data.data.web === "dengruicode.com") {

//get请求2
const response2 = await axios.get('http://127.0.0.1/article/get/id/1')
console.log("async.get2.data:", response2.data)
if (response2.data.data.name === "邓瑞") {

//get请求3
const response3 = await axios.get('http://127.0.0.1/article/get/search/title/入门')
console.log("async.get3.data:", response3.data)
}
}

} catch (error) {
console.log("async.get.error:", error)
} finally {
console.log("async.get.finally")
}
}

getData()

ES6
https://wainyz.online/wainyz/2024/06/15/ES6/
作者
wainyz
发布于
2024年6月15日
许可协议